-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
319660f
commit 8650769
Showing
10 changed files
with
403 additions
and
3 deletions.
There are no files selected for viewing
183 changes: 183 additions & 0 deletions
183
src/main/java/top/hendrixshen/tweakmyclient/compat/CompatMixinPlugin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
/* | ||
* Copyright (c) Copyright 2020 - 2022 The Cat Town Craft and contributors. | ||
* This source code is subject to the terms of the GNU Lesser General Public | ||
* License, version 3. If a copy of the LGPL was not distributed with this | ||
* file, You can obtain one at: https://www.gnu.org/licenses/lgpl-3.0.txt | ||
*/ | ||
package top.hendrixshen.tweakmyclient.compat; | ||
|
||
import com.google.common.collect.Lists; | ||
import net.fabricmc.tinyremapper.IMappingProvider.Member; | ||
import org.objectweb.asm.Opcodes; | ||
import org.objectweb.asm.tree.*; | ||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo; | ||
import org.spongepowered.asm.mixin.transformer.meta.MixinMerged; | ||
import org.spongepowered.asm.util.Annotations; | ||
import top.hendrixshen.tweakmyclient.TweakMyClientMixinPlugin; | ||
import top.hendrixshen.tweakmyclient.util.RemapUtil; | ||
import top.hendrixshen.tweakmyclient.util.mixin.MixinType; | ||
import top.hendrixshen.tweakmyclient.util.mixin.annotation.MagicAttack; | ||
import top.hendrixshen.tweakmyclient.util.mixin.annotation.MagicInterruption; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class CompatMixinPlugin extends TweakMyClientMixinPlugin { | ||
@Override | ||
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { | ||
super.postApply(targetClassName, targetClass, mixinClassName, mixinInfo); | ||
|
||
// Magical chanting. | ||
ClassNode mixinClass = mixinInfo.getClassNode(0); | ||
AnnotationNode magicInterruption = Annotations.getVisible(mixinClass, MagicInterruption.class); | ||
|
||
if (magicInterruption == null) { | ||
return; | ||
} | ||
|
||
for (MethodNode methodNode : mixinClass.methods) { | ||
AnnotationNode magicAttack = Annotations.getVisible(methodNode, MagicAttack.class); | ||
|
||
if (magicAttack == null) { | ||
continue; | ||
} | ||
|
||
this.jikuTsuiho(targetClass, methodNode, magicInterruption, magicAttack); | ||
} | ||
} | ||
|
||
/** | ||
* 時空追放. | ||
* <p>Erase target. | ||
* @param targetClass Injection target class. | ||
* @param magicAttackMethodNode Spell casting MethodNode. | ||
* @param magicInterruption Spell casting interruption AnnotationNode. | ||
* @param magicAttack Magical attacking AnnotationNode. | ||
*/ | ||
private void jikuTsuiho(ClassNode targetClass, MethodNode magicAttackMethodNode, AnnotationNode magicInterruption, AnnotationNode magicAttack) { | ||
List<Class<?>> tekitaiClass = Annotations.getValue(magicInterruption, "value", true); | ||
List<String> tekitaiTarget = Annotations.getValue(magicInterruption, "targets", true); | ||
|
||
ArrayList<String> tekitaiClasses = Lists.newArrayList(); | ||
for (Class<?> cls : tekitaiClass) { | ||
String s = cls.getName(); | ||
if (!tekitaiClasses.contains(s)) { | ||
tekitaiClasses.add(s); | ||
} | ||
} | ||
for (String s : tekitaiTarget) { | ||
if (!tekitaiClasses.contains(s)) { | ||
tekitaiClasses.add(s); | ||
} | ||
} | ||
|
||
MethodNode tekitaiMethod = this.findTekitaiMethod(targetClass, magicAttack, tekitaiClasses); | ||
|
||
if (tekitaiMethod == null) { | ||
return; | ||
} | ||
|
||
// Magic releasing. | ||
|
||
this.tsuihoTarget(targetClass, tekitaiMethod, magicAttackMethodNode, magicAttack); | ||
|
||
// Magic Harvesting. | ||
targetClass.visibleAnnotations.removeIf(annotationNode -> annotationNode.desc.equals("Ltop/catowncraft/carpettctcaddition/util/mixin/annotation/MagicInterruption;")); | ||
} | ||
|
||
/** | ||
* Find the enemy's MethodNode. | ||
* @param targetClass Injection target class. | ||
* @param magicAttack Spell casting MethodNode. | ||
* @param tekitaiTarget Enemy's class. | ||
* @return Enemy's MethodNode. | ||
*/ | ||
private MethodNode findTekitaiMethod(ClassNode targetClass, AnnotationNode magicAttack, ArrayList<String> tekitaiTarget) { | ||
List<MixinType> type = Annotations.getValue(magicAttack, "type", true, MixinType.class); | ||
String name = Annotations.getValue(magicAttack, "name"); | ||
int priority = Annotations.getValue(magicAttack, "priority", 1000); | ||
for (MethodNode methodNode : targetClass.methods) { | ||
if (!(methodNode.name.contains(type.get(0).getPrefix()) && methodNode.name.contains(name))) { | ||
continue; | ||
} | ||
|
||
AnnotationNode annotationNode = Annotations.getVisible(methodNode, MixinMerged.class); | ||
String mixin = Annotations.getValue(annotationNode, "mixin"); | ||
|
||
if (!tekitaiTarget.contains(mixin)) { | ||
continue; | ||
} | ||
|
||
int targetPriority = Annotations.getValue(annotationNode, "priority"); | ||
if (priority != targetPriority) { | ||
continue; | ||
} | ||
|
||
return methodNode; | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* Erase target and infuse soul. | ||
* @param targetClass Injection target ClassNode. | ||
* @param tekitaiMethodNode Enemy's MethodNode. | ||
* @param magicAttackMethodNode Spell casting MethodNode. | ||
* @param magicAttack Magical attacking AnnotationNode. | ||
*/ | ||
private void tsuihoTarget(ClassNode targetClass, MethodNode tekitaiMethodNode, MethodNode magicAttackMethodNode, AnnotationNode magicAttack) { | ||
String method = Annotations.getValue(magicAttack, "method"); | ||
String owner = Annotations.getValue(magicAttack, "owner"); | ||
String desc = Annotations.getValue(magicAttack, "desc"); | ||
Member remappedMethod = RemapUtil.mapMethod(owner, method, desc); | ||
int ordinal = Annotations.getValue(magicAttack, "ordinal", -1); | ||
boolean keep = Annotations.getValue(magicAttack, "keep", Boolean.FALSE); | ||
|
||
for (MethodNode methodNode : targetClass.methods) { | ||
if (methodNode.name.equals(remappedMethod.name) && methodNode.desc.equals(remappedMethod.desc)) { | ||
int offset = 0; | ||
int found = 0; | ||
int processed = 0; | ||
|
||
for(AbstractInsnNode abstractInsnNode : methodNode.instructions) { | ||
if (!(abstractInsnNode instanceof MethodInsnNode)) { | ||
continue; | ||
} | ||
|
||
MethodInsnNode methodInsnNode = (MethodInsnNode) abstractInsnNode; | ||
|
||
if (!methodInsnNode.name.equals(tekitaiMethodNode.name) || | ||
!methodInsnNode.desc.equals(tekitaiMethodNode.desc)) { | ||
continue; | ||
} | ||
|
||
if ((tekitaiMethodNode.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC && | ||
methodInsnNode.getOpcode() != Opcodes.INVOKESTATIC) { | ||
continue; | ||
} | ||
|
||
if ((tekitaiMethodNode.access & Opcodes.ACC_STATIC) == 0 && | ||
methodInsnNode.getOpcode() == Opcodes.INVOKESTATIC) { | ||
continue; | ||
} | ||
|
||
if (ordinal < 0 || ordinal == offset) { | ||
MethodInsnNode invokeMethod = new MethodInsnNode(methodInsnNode.getOpcode(), methodInsnNode.owner, | ||
magicAttackMethodNode.name, methodInsnNode.desc); | ||
methodNode.instructions.insertBefore(methodInsnNode, invokeMethod); | ||
methodNode.instructions.remove(methodInsnNode); | ||
processed++; | ||
} | ||
|
||
offset++; | ||
found++; | ||
|
||
if (found == processed && !keep) { | ||
targetClass.methods.remove(tekitaiMethodNode); | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
src/main/java/top/hendrixshen/tweakmyclient/compat/wurst/mixin/MixinLocalPlayer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package top.hendrixshen.tweakmyclient.compat.wurst.mixin; | ||
|
||
import net.minecraft.client.player.LocalPlayer; | ||
import net.minecraft.world.entity.EntityType; | ||
import net.minecraft.world.entity.LivingEntity; | ||
import net.minecraft.world.level.Level; | ||
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.Redirect; | ||
import top.hendrixshen.magiclib.dependency.annotation.Dependencies; | ||
import top.hendrixshen.magiclib.dependency.annotation.Dependency; | ||
import top.hendrixshen.tweakmyclient.config.Configs; | ||
import top.hendrixshen.tweakmyclient.util.mixin.MixinType; | ||
import top.hendrixshen.tweakmyclient.util.mixin.annotation.MagicAttack; | ||
import top.hendrixshen.tweakmyclient.util.mixin.annotation.MagicInterruption; | ||
|
||
@MagicInterruption(targets = "net.wurstclient.mixin.ClientPlayerEntityMixin") | ||
@Dependencies(and = @Dependency(value = "wurst")) | ||
@Mixin(value = LocalPlayer.class, priority = 1100) | ||
public abstract class MixinLocalPlayer extends LivingEntity { | ||
@Shadow | ||
private boolean startedUsingItem; | ||
|
||
protected MixinLocalPlayer(EntityType<? extends LivingEntity> entityType, Level level) { | ||
super(entityType, level); | ||
} | ||
|
||
@MagicAttack( | ||
type = MixinType.REDIRECT, | ||
name = "wurstIsUsingItem", | ||
owner = "class_1309", | ||
method = "method_6007", | ||
desc = "()V" | ||
) | ||
private boolean tmc$getUsingItemState(LocalPlayer instance) { | ||
if (Configs.disableSlowdown) { | ||
return false; | ||
} | ||
return this.startedUsingItem; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
src/main/java/top/hendrixshen/tweakmyclient/util/RemapUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package top.hendrixshen.tweakmyclient.util; | ||
|
||
import net.fabricmc.loader.api.FabricLoader; | ||
import net.fabricmc.loader.api.MappingResolver; | ||
import net.fabricmc.tinyremapper.IMappingProvider.Member; | ||
|
||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
public class RemapUtil { | ||
private static final Pattern CLASS_FINDER = Pattern.compile("Lnet\\/minecraft\\/([^;]+);"); | ||
private static final String INTERMEDIARY = "intermediary"; | ||
private static final MappingResolver RESOLVER = FabricLoader.getInstance().getMappingResolver(); | ||
|
||
private static String fromIntermediaryDot(String className) { | ||
return RESOLVER.mapClassName(INTERMEDIARY, String.format("net.minecraft.%s", className)); | ||
} | ||
|
||
public static String getClassName(String className) { | ||
return RemapUtil.fromIntermediaryDot(className).replace('.', '/'); | ||
} | ||
|
||
public static String getMethodName(String owner, String methodName, String desc) { | ||
return RemapUtil.RESOLVER.mapMethodName(INTERMEDIARY, "net.minecraft." + owner, methodName, desc); | ||
} | ||
|
||
public static Member mapMethod(String owner, String name, String desc) { | ||
return new Member(RemapUtil.getClassName(owner), RemapUtil.getMethodName(owner, name, desc), RemapUtil.mapMethodDescriptor(desc)); | ||
} | ||
|
||
public static String mapMethodDescriptor(String desc) { | ||
StringBuilder stringBuffer = new StringBuilder(); | ||
|
||
Matcher matcher = CLASS_FINDER.matcher(desc); | ||
while (matcher.find()) { | ||
matcher.appendReplacement(stringBuffer, Matcher.quoteReplacement('L' + RemapUtil.getClassName(matcher.group(1)) + ';')); | ||
} | ||
|
||
return matcher.appendTail(stringBuffer).toString(); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/main/java/top/hendrixshen/tweakmyclient/util/mixin/MixinType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* Copyright (c) Copyright 2020 - 2022 The Cat Town Craft and contributors. | ||
* This source code is subject to the terms of the GNU Lesser General Public | ||
* License, version 3. If a copy of the LGPL was not distributed with this | ||
* file, You can obtain one at: https://www.gnu.org/licenses/lgpl-3.0.txt | ||
*/ | ||
package top.hendrixshen.tweakmyclient.util.mixin; | ||
|
||
public enum MixinType { | ||
// ModifyVariable | ||
MODIFY_ARG("modify"), | ||
MODIFY_ARGS("args"), | ||
MODIFY_CONSTANT("constant"), | ||
MODIFY_VARIABLE("localvar"), | ||
REDIRECT("redirect"); | ||
|
||
private final String prefix; | ||
|
||
MixinType(String prefix) { | ||
this.prefix = prefix; | ||
} | ||
|
||
public String getPrefix() { | ||
return prefix; | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
src/main/java/top/hendrixshen/tweakmyclient/util/mixin/annotation/MagicAttack.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Copyright (c) Copyright 2020 - 2022 The Cat Town Craft and contributors. | ||
* This source code is subject to the terms of the GNU Lesser General Public | ||
* License, version 3. If a copy of the LGPL was not distributed with this | ||
* file, You can obtain one at: https://www.gnu.org/licenses/lgpl-3.0.txt | ||
*/ | ||
package top.hendrixshen.tweakmyclient.util.mixin.annotation; | ||
|
||
import top.hendrixshen.tweakmyclient.util.mixin.MixinType; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* You need magic to defeat magic. | ||
*/ | ||
@Target(ElementType.METHOD) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface MagicAttack { | ||
/** | ||
* The type of injector you want to erase the target. | ||
* @return Injector Type. | ||
*/ | ||
MixinType type(); | ||
|
||
/** | ||
* Name of the method you want to erase the target. | ||
* @return Target method name. | ||
*/ | ||
String name(); | ||
|
||
/** | ||
* From which owner you want to erase the target. Here you should use the intermediary name. | ||
* @return Source method owner. | ||
*/ | ||
String owner(); | ||
|
||
/** | ||
* From which method you want to erase the target. Here you should use the intermediary name. | ||
* @return Source method name. | ||
*/ | ||
String method(); | ||
|
||
/** | ||
* From which method you want to erase the target. Here you should use the intermediary name. | ||
* @return Source method desc. | ||
*/ | ||
String desc(); | ||
|
||
/** | ||
* The point at which you want to erase the target. | ||
* @return Offset(-1 means all). | ||
*/ | ||
int ordinal() default -1; | ||
|
||
/** | ||
* Priority of the method you want to erase the target. | ||
* @return Priority. | ||
*/ | ||
int priority() default 1000; | ||
|
||
/** | ||
* Whether to retain the target original injection. | ||
* @return Whether to keep. | ||
*/ | ||
boolean keep() default false; | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/java/top/hendrixshen/tweakmyclient/util/mixin/annotation/MagicInterruption.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Copyright (c) Copyright 2020 - 2022 The Cat Town Craft and contributors. | ||
* This source code is subject to the terms of the GNU Lesser General Public | ||
* License, version 3. If a copy of the LGPL was not distributed with this | ||
* file, You can obtain one at: https://www.gnu.org/licenses/lgpl-3.0.txt | ||
*/ | ||
package top.hendrixshen.tweakmyclient.util.mixin.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target(ElementType.TYPE) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface MagicInterruption { | ||
Class<?>[] value() default {}; | ||
|
||
String[] targets() default {}; | ||
} |
Oops, something went wrong.