Workaround OF breaking spectator hand mixin

This commit is contained in:
Jonas Herzig
2020-04-06 20:34:43 +02:00
parent 4c577c4559
commit ed6ba740bb
4 changed files with 121 additions and 2 deletions

View File

@@ -0,0 +1,75 @@
package com.replaymod.core;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.io.IOException;
import java.util.List;
import java.util.Set;
//#if MC>=11400
import java.io.InputStream;
//#else
//$$ import net.minecraft.launchwrapper.Launch;
//#endif
public class ReplayModMixinConfigPlugin implements IMixinConfigPlugin {
static boolean hasClass(String name) throws IOException {
//#if MC>=11400
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(name.replace('.', '/') + ".class");
if (stream != null) stream.close();
return stream != null;
//#else
//$$ return Launch.classLoader.getClassBytes(name) != null;
//#endif
}
private final Logger logger = LogManager.getLogger("replaymod/mixin");
private final boolean hasOF = hasClass("optifine.OptiFineForgeTweaker") || hasClass("me.modmuss50.optifabric.mod.Optifabric");
{
logger.error("hasOF: " + hasOF);
}
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
if (mixinClassName.endsWith("_OF")) return hasOF;
if (mixinClassName.endsWith("_NoOF")) return !hasOF;
return true;
}
@Override
public void onLoad(String mixinPackage) {
}
@Override
public String getRefMapperConfig() {
return null;
}
@Override
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
}
@Override
public List<String> getMixins() {
return null;
}
@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
}
public ReplayModMixinConfigPlugin() throws IOException {
}
}

View File

@@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.Redirect;
import static com.replaymod.core.versions.MCVer.getMinecraft;
@Mixin(GameRenderer.class)
public abstract class MixinGameRenderer {
public abstract class Mixin_ShowSpectatedHand_NoOF {
@Redirect(
method = "renderHand",
at = @At(

View File

@@ -0,0 +1,42 @@
//#if MC>=11400
package com.replaymod.replay.mixin;
import com.replaymod.replay.camera.CameraEntity;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
import net.minecraft.world.GameMode;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import static com.replaymod.core.versions.MCVer.getMinecraft;
@Pseudo
@Mixin(targets = "net.optifine.shaders.Shaders", remap = false)
public abstract class Mixin_ShowSpectatedHand_OF {
// OptiFine redirects renderHand to a new method with the same name but with more arguments
// since that method is only added by Optifabric, we can't inject our redirect in there (Mixin won't see it).
// So instead we fake the getCurrentGameMode for an entire section of the new renderHand method by injecting
// into `Shaders.setRenderingFirstPersonHand` which OF calls before and after our original target.
// We could also just inject into HEAD and RETURN of the original renderHand method but then we'd miss any calls
// which OF manually does to its method (and given it has extra parameters, I'd assume that it'll do some).
@Inject(method = "setRenderingFirstPersonHand", at = @At("HEAD"), remap = false)
private static void fakePlayerGameMode(boolean renderingHand, CallbackInfo ci) {
ClientPlayerEntity camera = getMinecraft().player;
if (camera instanceof CameraEntity) {
ClientPlayerInteractionManager interactionManager = getMinecraft().interactionManager;
assert interactionManager != null;
if (renderingHand) {
// alternative doesn't really matter, the caller only checks for equality to SPECTATOR
interactionManager.setGameMode(camera.isSpectator() ? GameMode.SPECTATOR : GameMode.SURVIVAL);
} else {
// reset back to spectator (we're always in spectator during a replay)
interactionManager.setGameMode(GameMode.SPECTATOR);
}
}
}
}
//#endif

View File

@@ -1,6 +1,7 @@
{
"required": true,
"package": "com.replaymod.replay.mixin",
"plugin": "com.replaymod.core.ReplayModMixinConfigPlugin",
"mixins": [],
"server": [],
"client": [
@@ -10,7 +11,8 @@
//#endif
"EntityLivingBaseAccessor",
//#if MC>=11400
"MixinGameRenderer",
"Mixin_ShowSpectatedHand_NoOF",
"Mixin_ShowSpectatedHand_OF",
//#else
//$$ "EntityOtherPlayerMPAccessor",
//#endif