mirror of
https://github.com/Wurst-Imperium/Wurst7.git
synced 2024-09-20 01:12:13 +02:00
Merge v7.44 into 1.20.6
This commit is contained in:
parent
6f6d767474
commit
4044a301c4
@ -1,6 +1,6 @@
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath "org.kohsuke:github-api:1.322"
|
||||
classpath "org.kohsuke:github-api:1.323"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ loader_version=0.15.11
|
||||
fabric_version=0.100.8+1.20.6
|
||||
|
||||
# Mod Properties
|
||||
mod_version = v7.44pre2-MC1.20.6
|
||||
mod_version = v7.44-MC1.20.6
|
||||
maven_group = net.wurstclient
|
||||
archives_base_name = Wurst-Client
|
||||
|
||||
|
@ -11,17 +11,10 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.IllegalFormatException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import net.wurstclient.altmanager.AltManager;
|
||||
import net.wurstclient.altmanager.Encryption;
|
||||
import net.wurstclient.analytics.WurstAnalytics;
|
||||
@ -41,7 +34,6 @@ import net.wurstclient.hack.HackList;
|
||||
import net.wurstclient.hud.IngameHUD;
|
||||
import net.wurstclient.keybinds.KeybindList;
|
||||
import net.wurstclient.keybinds.KeybindProcessor;
|
||||
import net.wurstclient.mixinterface.ILanguageManager;
|
||||
import net.wurstclient.mixinterface.IMinecraftClient;
|
||||
import net.wurstclient.navigator.Navigator;
|
||||
import net.wurstclient.other_feature.OtfList;
|
||||
@ -58,7 +50,7 @@ public enum WurstClient
|
||||
public static MinecraftClient MC;
|
||||
public static IMinecraftClient IMC;
|
||||
|
||||
public static final String VERSION = "7.44pre2";
|
||||
public static final String VERSION = "7.44";
|
||||
public static final String MC_VERSION = "1.20.6";
|
||||
|
||||
private WurstAnalytics analytics;
|
||||
@ -76,6 +68,7 @@ public enum WurstClient
|
||||
private IngameHUD hud;
|
||||
private RotationFaker rotationFaker;
|
||||
private FriendsList friends;
|
||||
private WurstTranslator translator;
|
||||
|
||||
private boolean enabled = true;
|
||||
private static boolean guiInitialized;
|
||||
@ -83,8 +76,6 @@ public enum WurstClient
|
||||
private ProblematicResourcePackDetector problematicPackDetector;
|
||||
private Path wurstFolder;
|
||||
|
||||
private KeyBinding zoomKey;
|
||||
|
||||
public void initialize()
|
||||
{
|
||||
System.out.println("Starting Wurst Client...");
|
||||
@ -126,6 +117,8 @@ public enum WurstClient
|
||||
friends = new FriendsList(friendsFile);
|
||||
friends.load();
|
||||
|
||||
translator = new WurstTranslator();
|
||||
|
||||
cmdProcessor = new CmdProcessor(cmds);
|
||||
eventManager.add(ChatOutputListener.class, cmdProcessor);
|
||||
|
||||
@ -150,10 +143,6 @@ public enum WurstClient
|
||||
Path encFolder = Encryption.chooseEncryptionFolder();
|
||||
altManager = new AltManager(altsFile, encFolder);
|
||||
|
||||
zoomKey = new KeyBinding("key.wurst.zoom", InputUtil.Type.KEYSYM,
|
||||
GLFW.GLFW_KEY_V, KeyBinding.MISC_CATEGORY);
|
||||
KeyBindingHelper.registerKeyBinding(zoomKey);
|
||||
|
||||
analytics.trackPageView("/mc" + MC_VERSION + "/v" + VERSION,
|
||||
"Wurst " + VERSION + " MC" + MC_VERSION);
|
||||
}
|
||||
@ -178,27 +167,7 @@ public enum WurstClient
|
||||
|
||||
public String translate(String key, Object... args)
|
||||
{
|
||||
if(otfs.translationsOtf.getForceEnglish().isChecked())
|
||||
{
|
||||
String string = ILanguageManager.getEnglish().get(key);
|
||||
|
||||
try
|
||||
{
|
||||
return String.format(string, args);
|
||||
|
||||
}catch(IllegalFormatException e)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
// This extra check is necessary because I18n.translate() doesn't
|
||||
// always return the key when the translation is missing. If the key
|
||||
// contains a '%', it will return "Format Error: key" instead.
|
||||
if(!I18n.hasTranslation(key))
|
||||
return key;
|
||||
|
||||
return I18n.translate(key, args);
|
||||
return translator.translate(key, args);
|
||||
}
|
||||
|
||||
public WurstAnalytics getAnalytics()
|
||||
@ -314,6 +283,11 @@ public enum WurstClient
|
||||
return friends;
|
||||
}
|
||||
|
||||
public WurstTranslator getTranslator()
|
||||
{
|
||||
return translator;
|
||||
}
|
||||
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
@ -345,11 +319,6 @@ public enum WurstClient
|
||||
return wurstFolder;
|
||||
}
|
||||
|
||||
public KeyBinding getZoomKey()
|
||||
{
|
||||
return zoomKey;
|
||||
}
|
||||
|
||||
public AltManager getAltManager()
|
||||
{
|
||||
return altManager;
|
||||
|
183
src/main/java/net/wurstclient/WurstTranslator.java
Normal file
183
src/main/java/net/wurstclient/WurstTranslator.java
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2024 Wurst-Imperium and contributors.
|
||||
*
|
||||
* This source code is subject to the terms of the GNU General Public
|
||||
* License, version 3. If a copy of the GPL was not distributed with this
|
||||
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
*/
|
||||
package net.wurstclient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.IllegalFormatException;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.resource.language.I18n;
|
||||
import net.minecraft.client.resource.language.TranslationStorage;
|
||||
import net.minecraft.resource.Resource;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.SynchronousResourceReloader;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Language;
|
||||
|
||||
public class WurstTranslator implements SynchronousResourceReloader
|
||||
{
|
||||
private final WurstClient wurst = WurstClient.INSTANCE;
|
||||
private TranslationStorage mcEnglish;
|
||||
|
||||
private final HashMap<String, String> englishOnlyStrings = new HashMap<>();
|
||||
private final HashMap<String, String> currentLangStrings = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void reload(ResourceManager manager)
|
||||
{
|
||||
mcEnglish = TranslationStorage.load(manager,
|
||||
Lists.newArrayList("en_us"), false);
|
||||
|
||||
currentLangStrings.clear();
|
||||
loadTranslations(manager, getCurrentLangCodes(),
|
||||
currentLangStrings::put);
|
||||
|
||||
englishOnlyStrings.clear();
|
||||
loadTranslations(manager, List.of("en_us"), englishOnlyStrings::put);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the given key with the given args into the current language,
|
||||
* or into English if the "Force English" setting is enabled. Both Wurst and
|
||||
* vanilla translations are supported.
|
||||
*/
|
||||
public String translate(String key, Object... args)
|
||||
{
|
||||
// Forced English
|
||||
if(isForcedEnglish())
|
||||
return translateEnglish(key, args);
|
||||
|
||||
// Wurst translation
|
||||
String string = currentLangStrings.get(key);
|
||||
if(string != null)
|
||||
try
|
||||
{
|
||||
return String.format(string, args);
|
||||
|
||||
}catch(IllegalFormatException e)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
// Vanilla translation
|
||||
return translateMc(key, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the given key with the given args into English, regardless of
|
||||
* the current language. Both Wurst and vanilla translations are supported.
|
||||
*/
|
||||
public String translateEnglish(String key, Object... args)
|
||||
{
|
||||
String string = englishOnlyStrings.get(key);
|
||||
if(string == null)
|
||||
string = mcEnglish.get(key);
|
||||
|
||||
try
|
||||
{
|
||||
return String.format(string, args);
|
||||
|
||||
}catch(IllegalFormatException e)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the given key with the given args into the current language,
|
||||
* or into English if the "Force English" setting is enabled, using only
|
||||
* Minecraft's own translations.
|
||||
*
|
||||
* @apiNote This method differs from
|
||||
* {@link I18n#translate(String, Object...)} in that it does not
|
||||
* return "Format error" if the key contains a percent sign.
|
||||
*/
|
||||
public String translateMc(String key, Object... args)
|
||||
{
|
||||
if(I18n.hasTranslation(key))
|
||||
return I18n.translate(key, args);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the given key with the given args into English, regardless of
|
||||
* the current language, using only Minecraft's own translations.
|
||||
*
|
||||
* @apiNote This method differs from
|
||||
* {@link I18n#translate(String, Object...)} in that it does not
|
||||
* return "Format error" if the key contains a percent sign.
|
||||
*/
|
||||
public String translateMcEnglish(String key, Object... args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return String.format(mcEnglish.get(key), args);
|
||||
|
||||
}catch(IllegalFormatException e)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isForcedEnglish()
|
||||
{
|
||||
return wurst.getOtfs().translationsOtf.getForceEnglish().isChecked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a translation storage for Minecraft's English strings, regardless
|
||||
* of the current language. Does not include any of Wurst's translations.
|
||||
*/
|
||||
public TranslationStorage getMcEnglish()
|
||||
{
|
||||
return mcEnglish;
|
||||
}
|
||||
|
||||
private ArrayList<String> getCurrentLangCodes()
|
||||
{
|
||||
String mainLangCode =
|
||||
MinecraftClient.getInstance().getLanguageManager().getLanguage();
|
||||
|
||||
ArrayList<String> langCodes = new ArrayList<>();
|
||||
langCodes.add("en_us");
|
||||
if(!"en_us".equals(mainLangCode))
|
||||
langCodes.add(mainLangCode);
|
||||
|
||||
return langCodes;
|
||||
}
|
||||
|
||||
private void loadTranslations(ResourceManager manager,
|
||||
Iterable<String> langCodes, BiConsumer<String, String> entryConsumer)
|
||||
{
|
||||
for(String langCode : langCodes)
|
||||
{
|
||||
String langFilePath = "translations/" + langCode + ".json";
|
||||
Identifier langId = Identifier.of("wurst", langFilePath);
|
||||
|
||||
for(Resource resource : manager.getAllResources(langId))
|
||||
try(InputStream stream = resource.getInputStream())
|
||||
{
|
||||
Language.load(stream, entryConsumer);
|
||||
|
||||
}catch(IOException e)
|
||||
{
|
||||
System.out.println("Failed to load translations for "
|
||||
+ langCode + " from pack " + resource.getPackId());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,11 +9,11 @@ package net.wurstclient.hacks.autolibrarian;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.client.resource.language.TranslationStorage;
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.wurstclient.mixinterface.ILanguageManager;
|
||||
import net.wurstclient.WurstClient;
|
||||
import net.wurstclient.WurstTranslator;
|
||||
|
||||
public record BookOffer(String id, int level, int price)
|
||||
implements Comparable<BookOffer>
|
||||
@ -31,19 +31,21 @@ public record BookOffer(String id, int level, int price)
|
||||
|
||||
public String getEnchantmentName()
|
||||
{
|
||||
TranslationStorage english = ILanguageManager.getEnglish();
|
||||
WurstTranslator translator = WurstClient.INSTANCE.getTranslator();
|
||||
Enchantment enchantment = getEnchantment();
|
||||
return english.get(enchantment.getTranslationKey());
|
||||
return translator.translateMcEnglish(enchantment.getTranslationKey());
|
||||
}
|
||||
|
||||
public String getEnchantmentNameWithLevel()
|
||||
{
|
||||
TranslationStorage english = ILanguageManager.getEnglish();
|
||||
WurstTranslator translator = WurstClient.INSTANCE.getTranslator();
|
||||
Enchantment enchantment = getEnchantment();
|
||||
String name = english.get(enchantment.getTranslationKey());
|
||||
String name =
|
||||
translator.translateMcEnglish(enchantment.getTranslationKey());
|
||||
|
||||
if(enchantment.getMaxLevel() > 1)
|
||||
name += " " + english.get("enchantment.level." + level);
|
||||
name += " "
|
||||
+ translator.translateMcEnglish("enchantment.level." + level);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
@ -9,10 +9,12 @@ package net.wurstclient.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
|
||||
import net.minecraft.client.network.ClientCommonNetworkHandler;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.listener.ClientCommonPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.wurstclient.event.EventManager;
|
||||
@ -22,15 +24,16 @@ import net.wurstclient.events.PacketOutputListener.PacketOutputEvent;
|
||||
public abstract class ClientCommonNetworkHandlerMixin
|
||||
implements ClientCommonPacketListener
|
||||
{
|
||||
@Inject(at = @At("HEAD"),
|
||||
method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V",
|
||||
cancellable = true)
|
||||
private void onSendPacket(Packet<?> packet, CallbackInfo ci)
|
||||
@WrapOperation(at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/network/ClientConnection;send(Lnet/minecraft/network/packet/Packet;)V"),
|
||||
method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V")
|
||||
private void wrapSendPacket(ClientConnection connection, Packet<?> packet,
|
||||
Operation<Void> original)
|
||||
{
|
||||
PacketOutputEvent event = new PacketOutputEvent(packet);
|
||||
EventManager.fire(event);
|
||||
|
||||
if(event.isCancelled())
|
||||
ci.cancel();
|
||||
if(!event.isCancelled())
|
||||
original.call(connection, event.getPacket());
|
||||
}
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2024 Wurst-Imperium and contributors.
|
||||
*
|
||||
* This source code is subject to the terms of the GNU General Public
|
||||
* License, version 3. If a copy of the GPL was not distributed with this
|
||||
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
*/
|
||||
package net.wurstclient.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.text.KeybindTextContent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TextContent;
|
||||
|
||||
@Mixin(KeybindTextContent.class)
|
||||
public abstract class KeybindTextContentMixin implements TextContent
|
||||
{
|
||||
@Shadow
|
||||
@Final
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* Ensures that any chat messages, written books, signs, etc. cannot resolve
|
||||
* Wurst-related keybinds.
|
||||
*
|
||||
* <p>
|
||||
* Fixes at least one security vulnerability affecting Minecraft 1.20 and
|
||||
* later versions, where the server can detect the presence of Wurst by
|
||||
* abusing Minecraft's sign editing feature. When a player edits a sign, any
|
||||
* translated text and keybind text components on that sign are resolved by
|
||||
* the client and sent back to the server as plain text. This allows the
|
||||
* server to detect the presence of non-vanilla keybinds, such as Wurst's
|
||||
* zoom keybind.
|
||||
*
|
||||
* <p>
|
||||
* It is likely that similar vulnerabilities exist or will exist in other
|
||||
* parts of the game, such as chat messages and written books. Mojang has a
|
||||
* long history of failing to properly secure their text component system
|
||||
* (see BookHack, OP-Sign, BookDupe). Therefore it's best to cut off this
|
||||
* entire attack vector at the source.
|
||||
*/
|
||||
@Inject(at = @At("RETURN"),
|
||||
method = "getTranslated()Lnet/minecraft/text/Text;",
|
||||
cancellable = true)
|
||||
private void onGetTranslated(CallbackInfoReturnable<Text> cir)
|
||||
{
|
||||
if(key != null && key.contains("wurst"))
|
||||
cir.setReturnValue(Text.literal(key));
|
||||
}
|
||||
}
|
@ -12,31 +12,21 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.minecraft.client.resource.language.LanguageManager;
|
||||
import net.minecraft.client.resource.language.TranslationStorage;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.resource.SynchronousResourceReloader;
|
||||
import net.wurstclient.mixinterface.ILanguageManager;
|
||||
import net.wurstclient.WurstClient;
|
||||
|
||||
@Mixin(LanguageManager.class)
|
||||
public abstract class LanguageManagerMixin
|
||||
implements SynchronousResourceReloader, ILanguageManager
|
||||
implements SynchronousResourceReloader
|
||||
{
|
||||
private TranslationStorage wurstEnglish;
|
||||
|
||||
@Inject(at = @At("HEAD"),
|
||||
method = "reload(Lnet/minecraft/resource/ResourceManager;)V")
|
||||
private void onReload(ResourceManager manager, CallbackInfo ci)
|
||||
{
|
||||
wurstEnglish = TranslationStorage.load(manager,
|
||||
Lists.newArrayList("en_us"), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TranslationStorage wurst_getEnglish()
|
||||
{
|
||||
return wurstEnglish;
|
||||
// Using a mixin for this because WurstClient.initialize() runs too
|
||||
// early to call ResourceManager.registerReloader()
|
||||
WurstClient.INSTANCE.getTranslator().reload(manager);
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,11 @@ package net.wurstclient.mixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
|
||||
import net.minecraft.client.render.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.render.entity.LivingEntityRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
@ -25,16 +27,17 @@ public abstract class LivingEntityRendererMixin
|
||||
/**
|
||||
* Disables the distance limit in hasLabel() if configured in NameTags.
|
||||
*/
|
||||
@Redirect(at = @At(value = "INVOKE",
|
||||
@WrapOperation(at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/render/entity/EntityRenderDispatcher;getSquaredDistanceToCamera(Lnet/minecraft/entity/Entity;)D",
|
||||
ordinal = 0), method = "hasLabel(Lnet/minecraft/entity/LivingEntity;)Z")
|
||||
private double adjustDistance(EntityRenderDispatcher render, Entity entity)
|
||||
private double adjustDistance(EntityRenderDispatcher render, Entity entity,
|
||||
Operation<Double> original)
|
||||
{
|
||||
// pretend the distance is 1 so the check always passes
|
||||
if(WurstClient.INSTANCE.getHax().nameTagsHack.isUnlimitedRange())
|
||||
return 1;
|
||||
|
||||
return render.getSquaredDistanceToCamera(entity);
|
||||
return original.call(render, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +65,14 @@ public abstract class MinecraftClientMixin
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "handleInputEvents()V")
|
||||
/**
|
||||
* Runs just before {@link MinecraftClient#handleInputEvents()}, bypassing
|
||||
* the <code>overlay == null && currentScreen == null</code> check in
|
||||
* {@link MinecraftClient#tick()}.
|
||||
*/
|
||||
@Inject(at = @At(value = "FIELD",
|
||||
target = "Lnet/minecraft/client/MinecraftClient;overlay:Lnet/minecraft/client/gui/screen/Overlay;",
|
||||
ordinal = 0), method = "tick()V")
|
||||
private void onHandleInputEvents(CallbackInfo ci)
|
||||
{
|
||||
EventManager.fire(HandleInputEvent.INSTANCE);
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2024 Wurst-Imperium and contributors.
|
||||
*
|
||||
* This source code is subject to the terms of the GNU General Public
|
||||
* License, version 3. If a copy of the GPL was not distributed with this
|
||||
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
*/
|
||||
package net.wurstclient.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
|
||||
import net.minecraft.text.TextContent;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
import net.minecraft.util.Language;
|
||||
|
||||
@Mixin(TranslatableTextContent.class)
|
||||
public abstract class TranslatableTextContentMixin implements TextContent
|
||||
{
|
||||
/**
|
||||
* Ensures that any chat messages, written books, signs, etc. cannot resolve
|
||||
* Wurst-related translation keys.
|
||||
*
|
||||
* <p>
|
||||
* Fixes at least one security vulnerability affecting Minecraft 1.20 and
|
||||
* later versions, where the server can detect the presence of Wurst by
|
||||
* abusing Minecraft's sign editing feature. When a player edits a sign, any
|
||||
* translated text and keybind text components on that sign are resolved by
|
||||
* the client and sent back to the server as plain text. This allows the
|
||||
* server to detect the presence of non-vanilla translation keys.
|
||||
*
|
||||
* <p>
|
||||
* It is likely that similar vulnerabilities exist or will exist in other
|
||||
* parts of the game, such as chat messages and written books. Mojang has a
|
||||
* long history of failing to properly secure their text component system
|
||||
* (see BookHack, OP-Sign, BookDupe). Therefore it's best to cut off this
|
||||
* entire attack vector at the source.
|
||||
*/
|
||||
@WrapOperation(at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/Language;get(Ljava/lang/String;)Ljava/lang/String;",
|
||||
ordinal = 0), method = "updateTranslations()V")
|
||||
private String translate(Language instance, String key,
|
||||
Operation<String> original)
|
||||
{
|
||||
if(key != null && key.contains("wurst"))
|
||||
return key;
|
||||
|
||||
return original.call(instance, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above, but for translatable text components with a fallback.
|
||||
*/
|
||||
@WrapOperation(at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/Language;get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
|
||||
ordinal = 0), method = "updateTranslations()V")
|
||||
private String translateWithFallback(Language instance, String key,
|
||||
String fallback, Operation<String> original)
|
||||
{
|
||||
if(key != null && key.contains("wurst"))
|
||||
return fallback;
|
||||
|
||||
return original.call(instance, key, fallback);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2024 Wurst-Imperium and contributors.
|
||||
*
|
||||
* This source code is subject to the terms of the GNU General Public
|
||||
* License, version 3. If a copy of the GPL was not distributed with this
|
||||
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
*/
|
||||
package net.wurstclient.mixinterface;
|
||||
|
||||
import net.minecraft.client.resource.language.TranslationStorage;
|
||||
import net.wurstclient.WurstClient;
|
||||
|
||||
public interface ILanguageManager
|
||||
{
|
||||
public TranslationStorage wurst_getEnglish();
|
||||
|
||||
public static TranslationStorage getEnglish()
|
||||
{
|
||||
return ((ILanguageManager)WurstClient.MC.getLanguageManager())
|
||||
.wurst_getEnglish();
|
||||
}
|
||||
}
|
@ -11,8 +11,6 @@ import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.Drawable;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import net.minecraft.text.Text;
|
||||
import net.wurstclient.WurstClient;
|
||||
import net.wurstclient.other_features.ZoomOtf;
|
||||
@ -22,7 +20,6 @@ import net.wurstclient.settings.SliderSetting;
|
||||
public class ZoomManagerScreen extends Screen implements PressAKeyCallback
|
||||
{
|
||||
private Screen prevScreen;
|
||||
private ButtonWidget keyButton;
|
||||
private ButtonWidget scrollButton;
|
||||
|
||||
public ZoomManagerScreen(Screen par1GuiScreen)
|
||||
@ -38,15 +35,16 @@ public class ZoomManagerScreen extends Screen implements PressAKeyCallback
|
||||
ZoomOtf zoom = wurst.getOtfs().zoomOtf;
|
||||
SliderSetting level = zoom.getLevelSetting();
|
||||
CheckboxSetting scroll = zoom.getScrollSetting();
|
||||
Text zoomKeyName = wurst.getZoomKey().getBoundKeyLocalizedText();
|
||||
|
||||
addDrawableChild(ButtonWidget
|
||||
.builder(Text.literal("Back"), b -> client.setScreen(prevScreen))
|
||||
.dimensions(width / 2 - 100, height / 4 + 144 - 16, 200, 20)
|
||||
.build());
|
||||
|
||||
addDrawableChild(keyButton = ButtonWidget
|
||||
.builder(Text.literal("Zoom Key: ").append(zoomKeyName),
|
||||
addDrawableChild(ButtonWidget
|
||||
.builder(
|
||||
Text.literal("Zoom Key: ")
|
||||
.append(zoom.getTranslatedKeybindName()),
|
||||
b -> client.setScreen(new PressAKeyScreen(this)))
|
||||
.dimensions(width / 2 - 79, height / 4 + 24 - 16, 158, 20).build());
|
||||
|
||||
@ -115,10 +113,8 @@ public class ZoomManagerScreen extends Screen implements PressAKeyCallback
|
||||
@Override
|
||||
public void setKey(String key)
|
||||
{
|
||||
WurstClient.INSTANCE.getZoomKey()
|
||||
.setBoundKey(InputUtil.fromTranslationKey(key));
|
||||
client.options.write();
|
||||
KeyBinding.updateKeysByCode();
|
||||
keyButton.setMessage(Text.literal("Zoom Key: " + key));
|
||||
WurstClient.INSTANCE.getOtfs().zoomOtf.setBoundKey(key);
|
||||
// Button text updates automatically because going back to this screen
|
||||
// calls init(). Might be different in older MC versions.
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@
|
||||
package net.wurstclient.other_features;
|
||||
|
||||
import net.minecraft.client.option.SimpleOption;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import net.minecraft.text.Text;
|
||||
import net.wurstclient.DontBlock;
|
||||
import net.wurstclient.SearchTags;
|
||||
import net.wurstclient.events.MouseScrollListener;
|
||||
@ -15,6 +17,7 @@ import net.wurstclient.other_feature.OtherFeature;
|
||||
import net.wurstclient.settings.CheckboxSetting;
|
||||
import net.wurstclient.settings.SliderSetting;
|
||||
import net.wurstclient.settings.SliderSetting.ValueDisplay;
|
||||
import net.wurstclient.settings.TextFieldSetting;
|
||||
import net.wurstclient.util.MathUtils;
|
||||
|
||||
@SearchTags({"telescope", "optifine"})
|
||||
@ -25,10 +28,16 @@ public final class ZoomOtf extends OtherFeature implements MouseScrollListener
|
||||
50, 0.1, ValueDisplay.DECIMAL.withSuffix("x"));
|
||||
|
||||
private final CheckboxSetting scroll = new CheckboxSetting(
|
||||
"Use mouse wheel",
|
||||
"If enabled, you can use the mouse wheel while zooming to zoom in even further.",
|
||||
"Use mouse wheel", "If enabled, you can use the mouse wheel while"
|
||||
+ " zooming to zoom in even further.",
|
||||
true);
|
||||
|
||||
private final TextFieldSetting keybind = new TextFieldSetting("Keybind",
|
||||
"Determines the zoom keybind.\n\n"
|
||||
+ "Instead of editing this value manually, you should go to Wurst"
|
||||
+ " Options -> Zoom and set it there.",
|
||||
"key.keyboard.v", this::isValidKeybind);
|
||||
|
||||
private Double currentLevel;
|
||||
private Double defaultMouseSensitivity;
|
||||
|
||||
@ -39,6 +48,7 @@ public final class ZoomOtf extends OtherFeature implements MouseScrollListener
|
||||
+ "Go to Wurst Options -> Zoom to change this keybind.");
|
||||
addSetting(level);
|
||||
addSetting(scroll);
|
||||
addSetting(keybind);
|
||||
EVENTS.add(MouseScrollListener.class, this);
|
||||
}
|
||||
|
||||
@ -50,7 +60,7 @@ public final class ZoomOtf extends OtherFeature implements MouseScrollListener
|
||||
if(currentLevel == null)
|
||||
currentLevel = level.getValue();
|
||||
|
||||
if(!WURST.getZoomKey().isPressed())
|
||||
if(!isZoomKeyPressed())
|
||||
{
|
||||
currentLevel = level.getValue();
|
||||
|
||||
@ -78,7 +88,7 @@ public final class ZoomOtf extends OtherFeature implements MouseScrollListener
|
||||
@Override
|
||||
public void onMouseScroll(double amount)
|
||||
{
|
||||
if(!WURST.getZoomKey().isPressed() || !scroll.isChecked())
|
||||
if(!isZoomKeyPressed() || !scroll.isChecked())
|
||||
return;
|
||||
|
||||
if(currentLevel == null)
|
||||
@ -95,7 +105,36 @@ public final class ZoomOtf extends OtherFeature implements MouseScrollListener
|
||||
|
||||
public boolean shouldPreventHotbarScrolling()
|
||||
{
|
||||
return WURST.getZoomKey().isPressed() && scroll.isChecked();
|
||||
return isZoomKeyPressed() && scroll.isChecked();
|
||||
}
|
||||
|
||||
public Text getTranslatedKeybindName()
|
||||
{
|
||||
return InputUtil.fromTranslationKey(keybind.getValue())
|
||||
.getLocalizedText();
|
||||
}
|
||||
|
||||
public void setBoundKey(String translationKey)
|
||||
{
|
||||
keybind.setValue(translationKey);
|
||||
}
|
||||
|
||||
private boolean isZoomKeyPressed()
|
||||
{
|
||||
return InputUtil.isKeyPressed(MC.getWindow().getHandle(),
|
||||
InputUtil.fromTranslationKey(keybind.getValue()).getCode());
|
||||
}
|
||||
|
||||
private boolean isValidKeybind(String keybind)
|
||||
{
|
||||
try
|
||||
{
|
||||
return InputUtil.fromTranslationKey(keybind) != null;
|
||||
|
||||
}catch(IllegalArgumentException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public SliderSetting getLevelSetting()
|
||||
|
@ -40,7 +40,6 @@
|
||||
"IngameHudMixin",
|
||||
"InGameOverlayRendererMixin",
|
||||
"KeyBindingMixin",
|
||||
"KeybindTextContentMixin",
|
||||
"KeyboardMixin",
|
||||
"LanguageManagerMixin",
|
||||
"LivingEntityRendererMixin",
|
||||
@ -63,7 +62,6 @@
|
||||
"TelemetryManagerMixin",
|
||||
"TextVisitFactoryMixin",
|
||||
"TitleScreenMixin",
|
||||
"TranslatableTextContentMixin",
|
||||
"WorldMixin",
|
||||
"WorldRendererMixin"
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user