diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6373e4bc..f3942d43 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -11,7 +11,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@main + - uses: actions/stale@v9 with: stale-issue-message: | This issue has been open for a while with no recent activity. If this issue is still important to you, please add a comment within the next 7 days to keep it open. Otherwise, the issue will be automatically closed to free up time for other tasks. @@ -31,7 +31,9 @@ jobs: - They have bugs or conflicts that won't be resolved days-before-stale: 60 days-before-close: 7 + exempt-issue-labels: "status:never-stale" + exempt-pr-labels: "status:never-stale" stale-issue-label: "status:stale" stale-pr-label: "status:stale" - operations-per-run: 50 + operations-per-run: 200 enable-statistics: true diff --git a/codestyle/cleanup.xml b/codestyle/cleanup.xml index 70a36773..a6aa8d3e 100644 --- a/codestyle/cleanup.xml +++ b/codestyle/cleanup.xml @@ -1,144 +1,147 @@ - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/codestyle/formatter.xml b/codestyle/formatter.xml index b44984ad..3c2ecb64 100644 --- a/codestyle/formatter.xml +++ b/codestyle/formatter.xml @@ -200,6 +200,7 @@ + @@ -280,6 +281,7 @@ + @@ -310,6 +312,7 @@ + diff --git a/src/main/java/net/wurstclient/commands/PotionCmd.java b/src/main/java/net/wurstclient/commands/PotionCmd.java index 5ecb99da..fd8ddc67 100644 --- a/src/main/java/net/wurstclient/commands/PotionCmd.java +++ b/src/main/java/net/wurstclient/commands/PotionCmd.java @@ -7,15 +7,15 @@ */ package net.wurstclient.commands; -import java.util.List; +import java.util.ArrayList; import net.minecraft.entity.effect.StatusEffect; import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.item.ItemStack; import net.minecraft.item.PotionItem; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtList; +import net.minecraft.potion.Potion; import net.minecraft.potion.PotionUtil; +import net.minecraft.potion.Potions; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; import net.minecraft.util.InvalidIdentifierException; @@ -60,15 +60,18 @@ public final class PotionCmd extends Command throw new CmdSyntaxError(); // get effects to start with - NbtList effects; + ArrayList effects; + Potion potion; switch(args[0].toLowerCase()) { case "add": - effects = convertEffectsToNbt(stack); + effects = new ArrayList<>(PotionUtil.getCustomPotionEffects(stack)); + potion = PotionUtil.getPotion(stack); break; case "set": - effects = new NbtList(); + effects = new ArrayList<>(); + potion = Potions.EMPTY; break; default: @@ -78,96 +81,75 @@ public final class PotionCmd extends Command // add new effects for(int i = 0; i < (args.length - 1) / 3; i++) { - NbtCompound effect = new NbtCompound(); + StatusEffect effect = parseEffect(args[1 + i * 3]); + int amplifier = parseInt(args[2 + i * 3]) - 1; + int duration = parseInt(args[3 + i * 3]) * 20; - effect.putInt("Id", parseEffectId(args[1 + i * 3])); - effect.putInt("Amplifier", parseInt(args[2 + i * 3]) - 1); - effect.putInt("Duration", parseInt(args[3 + i * 3]) * 20); - - effects.add(effect); + effects.add(new StatusEffectInstance(effect, duration, amplifier)); } - NbtCompound nbt = new NbtCompound(); - nbt.put("CustomPotionEffects", effects); - stack.setNbt(nbt); + PotionUtil.setPotion(stack, potion); + setCustomPotionEffects(stack, effects); ChatUtils.message("Potion modified."); } - private NbtList convertEffectsToNbt(ItemStack stack) - { - NbtList nbt = new NbtList(); - List effects = - PotionUtil.getCustomPotionEffects(stack); - - for(StatusEffectInstance effect : effects) - { - NbtCompound tag = new NbtCompound(); - - int id = StatusEffect.getRawId(effect.getEffectType()); - tag.putInt("Id", id); - tag.putInt("Amplifier", effect.getAmplifier()); - tag.putInt("Duration", effect.getDuration()); - - nbt.add(tag); - } - - return nbt; - } - private void remove(ItemStack stack, String[] args) throws CmdSyntaxError { if(args.length != 2) throw new CmdSyntaxError(); - int id = parseEffectId(args[1]); + StatusEffect targetEffect = parseEffect(args[1]); - List oldEffects = - PotionUtil.getCustomPotionEffects(stack); + Potion oldPotion = PotionUtil.getPotion(stack); + boolean mainPotionContainsTargetEffect = oldPotion.getEffects().stream() + .anyMatch(effect -> effect.getEffectType() == targetEffect); - NbtList newEffects = new NbtList(); - for(StatusEffectInstance oldEffect : oldEffects) - { - int oldId = StatusEffect.getRawId(oldEffect.getEffectType()); - - if(oldId == id) - continue; - - NbtCompound effect = new NbtCompound(); - effect.putInt("Id", oldId); - effect.putInt("Amplifier", oldEffect.getAmplifier()); - effect.putInt("Duration", oldEffect.getDuration()); - newEffects.add(effect); - } + ArrayList newEffects = new ArrayList<>(); + if(mainPotionContainsTargetEffect) + PotionUtil.getPotionEffects(stack).forEach(newEffects::add); + else + PotionUtil.getCustomPotionEffects(stack).forEach(newEffects::add); + newEffects.removeIf(effect -> effect.getEffectType() == targetEffect); - NbtCompound nbt = new NbtCompound(); - nbt.put("CustomPotionEffects", newEffects); - stack.setNbt(nbt); + Potion newPotion = + mainPotionContainsTargetEffect ? Potions.EMPTY : oldPotion; + + PotionUtil.setPotion(stack, newPotion); + setCustomPotionEffects(stack, newEffects); ChatUtils.message("Effect removed."); } - private int parseEffectId(String input) throws CmdSyntaxError + private StatusEffect parseEffect(String input) throws CmdSyntaxError { - int id = 0; + StatusEffect effect; if(MathUtils.isInteger(input)) - id = Integer.parseInt(input); + effect = Registries.STATUS_EFFECT.get(Integer.parseInt(input)); else try { Identifier identifier = new Identifier(input); - StatusEffect effect = Registries.STATUS_EFFECT.get(identifier); - - id = StatusEffect.getRawId(effect); + effect = Registries.STATUS_EFFECT.get(identifier); }catch(InvalidIdentifierException e) { throw new CmdSyntaxError("Invalid effect: " + input); } - if(id < 1) - throw new CmdSyntaxError(); + if(effect == null) + throw new CmdSyntaxError("Invalid effect: " + input); - return id; + return Registries.STATUS_EFFECT.getEntry(effect).value(); + } + + private void setCustomPotionEffects(ItemStack stack, + ArrayList effects) + { + // PotionUtil doesn't remove effects when passing an empty list to it + if(effects.isEmpty()) + stack.removeSubNbt("CustomPotionEffects"); + else + PotionUtil.setCustomPotionEffects(stack, effects); } private int parseInt(String s) throws CmdSyntaxError diff --git a/src/main/java/net/wurstclient/hacks/AntiSpamHack.java b/src/main/java/net/wurstclient/hacks/AntiSpamHack.java index efae48f6..16aed807 100644 --- a/src/main/java/net/wurstclient/hacks/AntiSpamHack.java +++ b/src/main/java/net/wurstclient/hacks/AntiSpamHack.java @@ -135,7 +135,17 @@ public final class AntiSpamHack extends Hack implements ChatInputListener } if(spamCounter > 1) - event.setComponent(((MutableText)event.getComponent()) - .append(" [x" + spamCounter + "]")); + { + // Someone, somewhere, is creating a MutableText object with an + // immutable List siblings parameter, which causes the game to + // crash when calling append(). So we always have to create a new + // MutableText object to avoid that. + MutableText oldText = (MutableText)event.getComponent(); + MutableText newText = MutableText.of(oldText.getContent()); + newText.setStyle(oldText.getStyle()); + oldText.getSiblings().forEach(newText::append); + + event.setComponent(newText.append(" [x" + spamCounter + "]")); + } } } diff --git a/src/main/java/net/wurstclient/hacks/AutoLibrarianHack.java b/src/main/java/net/wurstclient/hacks/AutoLibrarianHack.java index 0f1345be..2f49d3c2 100644 --- a/src/main/java/net/wurstclient/hacks/AutoLibrarianHack.java +++ b/src/main/java/net/wurstclient/hacks/AutoLibrarianHack.java @@ -418,7 +418,7 @@ public final class AutoLibrarianHack extends Hack for(TradeOffer tradeOffer : tradeOffers) { ItemStack stack = tradeOffer.getSellItem(); - if(!(stack.getItem() instanceof EnchantedBookItem book)) + if(!(stack.getItem() instanceof EnchantedBookItem)) continue; NbtList enchantmentNbt = EnchantedBookItem.getEnchantmentNbt(stack); diff --git a/src/main/java/net/wurstclient/mixin/PlayerSkinProviderMixin.java b/src/main/java/net/wurstclient/mixin/PlayerSkinProviderMixin.java index f2f64137..fadc762b 100644 --- a/src/main/java/net/wurstclient/mixin/PlayerSkinProviderMixin.java +++ b/src/main/java/net/wurstclient/mixin/PlayerSkinProviderMixin.java @@ -7,8 +7,6 @@ */ package net.wurstclient.mixin; -import java.io.InputStreamReader; -import java.net.URL; import java.util.HashMap; import javax.annotation.Nullable; @@ -22,8 +20,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import com.mojang.authlib.GameProfile; import com.mojang.authlib.minecraft.InsecurePublicKeyException; import com.mojang.authlib.minecraft.MinecraftProfileTexture; @@ -35,6 +31,8 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.texture.PlayerSkinProvider; import net.minecraft.util.Identifier; import net.minecraft.util.Util; +import net.wurstclient.util.json.JsonUtils; +import net.wurstclient.util.json.WsonObject; @Mixin(PlayerSkinProvider.class) public abstract class PlayerSkinProviderMixin @@ -43,7 +41,7 @@ public abstract class PlayerSkinProviderMixin @Final private MinecraftSessionService sessionService; - private static JsonObject capes; + private static HashMap capes; @Inject(at = @At("HEAD"), method = "loadSkin(Lcom/mojang/authlib/GameProfile;Lnet/minecraft/client/texture/PlayerSkinProvider$SkinTextureAvailableCallback;Z)V", @@ -116,14 +114,14 @@ public abstract class PlayerSkinProviderMixin if(capes == null) setupWurstCapes(); - if(capes.has(name)) + if(capes.containsKey(name)) { - String capeURL = capes.get(name).getAsString(); + String capeURL = capes.get(name); map.put(Type.CAPE, new MinecraftProfileTexture(capeURL, null)); - }else if(capes.has(uuid)) + }else if(capes.containsKey(uuid)) { - String capeURL = capes.get(uuid).getAsString(); + String capeURL = capes.get(uuid); map.put(Type.CAPE, new MinecraftProfileTexture(capeURL, null)); } @@ -140,12 +138,11 @@ public abstract class PlayerSkinProviderMixin { try { - // TODO: download capes to file - URL url = new URL("https://www.wurstclient.net/api/v1/capes.json"); + // download cape list from wurstclient.net + WsonObject rawCapes = JsonUtils.parseURLToObject( + "https://www.wurstclient.net/api/v1/capes.json"); - capes = - JsonParser.parseReader(new InputStreamReader(url.openStream())) - .getAsJsonObject(); + capes = rawCapes.getAllStrings(); }catch(Exception e) {