├── .gitignore ├── build.gradle └── src └── main └── java └── net └── canelex └── perspectivemod ├── LoadingPlugin.java ├── PerspectiveMod.java ├── asm ├── CameraTransformer.java ├── CameraVisitor.java └── OrientCameraVisitor.java └── command └── CommandPerspectiveSettings.java /.gitignore: -------------------------------------------------------------------------------- 1 | # non-src 2 | /* 3 | !/src 4 | 5 | # build 6 | !build.gradle 7 | 8 | 9 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | maven { 5 | name = "forge" 6 | url = "http://files.minecraftforge.net/maven" 7 | } 8 | maven { 9 | name = "sonatype" 10 | url = "https://oss.sonatype.org/content/repositories/snapshots/" 11 | } 12 | } 13 | dependencies { 14 | classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT' 15 | } 16 | } 17 | 18 | apply plugin: 'forge' 19 | 20 | version = "3.0" 21 | group= "net.canelex.perspectivemod" // http://maven.apache.org/guides/mini/guide-naming-conventions.html 22 | archivesBaseName = "Perspective Mod" 23 | 24 | minecraft { 25 | version = "1.7.10-10.13.4.1558-1.7.10" 26 | runDir = "eclipse" 27 | } 28 | 29 | dependencies { 30 | // you may put jars on which you depend on in ./libs 31 | // or you may define them like so.. 32 | //compile "some.group:artifact:version:classifier" 33 | //compile "some.group:artifact:version" 34 | 35 | // real examples 36 | //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env 37 | //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env 38 | 39 | // for more info... 40 | // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html 41 | // http://www.gradle.org/docs/current/userguide/dependency_management.html 42 | 43 | } 44 | 45 | processResources 46 | { 47 | // this will ensure that this task is redone when the versions change. 48 | inputs.property "version", project.version 49 | inputs.property "mcversion", project.minecraft.version 50 | 51 | // replace stuff in mcmod.info, nothing else 52 | from(sourceSets.main.resources.srcDirs) { 53 | include 'mcmod.info' 54 | 55 | // replace version and mcversion 56 | expand 'version':project.version, 'mcversion':project.minecraft.version 57 | } 58 | 59 | // copy everything else, thats not the mcmod.info 60 | from(sourceSets.main.resources.srcDirs) { 61 | exclude 'mcmod.info' 62 | } 63 | } 64 | 65 | jar 66 | { 67 | manifest 68 | { 69 | attributes("FMLCorePlugin": "net.canelex.perspectivemod.LoadingPlugin") 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/net/canelex/perspectivemod/LoadingPlugin.java: -------------------------------------------------------------------------------- 1 | package net.canelex.perspectivemod; 2 | 3 | import cpw.mods.fml.relauncher.IFMLLoadingPlugin; 4 | import net.canelex.perspectivemod.asm.CameraTransformer; 5 | 6 | import java.util.Map; 7 | 8 | @IFMLLoadingPlugin.Name("Perspective Mod") 9 | @IFMLLoadingPlugin.MCVersion("1.7.10") 10 | public class LoadingPlugin implements IFMLLoadingPlugin 11 | { 12 | @Override public String[] getASMTransformerClass() 13 | { 14 | return new String[]{ CameraTransformer.class.getName() }; 15 | } 16 | 17 | @Override public String getModContainerClass() 18 | { 19 | return PerspectiveMod.class.getName(); 20 | } 21 | 22 | @Override public String getSetupClass() 23 | { 24 | return null; 25 | } 26 | 27 | @Override public String getAccessTransformerClass() 28 | { 29 | return null; 30 | } 31 | 32 | @Override public void injectData(Map data) 33 | { 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/canelex/perspectivemod/PerspectiveMod.java: -------------------------------------------------------------------------------- 1 | package net.canelex.perspectivemod; 2 | 3 | import com.google.common.eventbus.EventBus; 4 | import com.google.common.eventbus.Subscribe; 5 | import cpw.mods.fml.client.registry.ClientRegistry; 6 | import cpw.mods.fml.common.DummyModContainer; 7 | import cpw.mods.fml.common.FMLCommonHandler; 8 | import cpw.mods.fml.common.LoadController; 9 | import cpw.mods.fml.common.ModMetadata; 10 | import cpw.mods.fml.common.event.FMLInitializationEvent; 11 | import cpw.mods.fml.common.eventhandler.SubscribeEvent; 12 | import cpw.mods.fml.common.gameevent.InputEvent; 13 | import net.canelex.perspectivemod.command.CommandPerspectiveSettings; 14 | import net.minecraft.client.Minecraft; 15 | import net.minecraft.client.renderer.EntityRenderer; 16 | import net.minecraft.client.settings.KeyBinding; 17 | import net.minecraftforge.client.ClientCommandHandler; 18 | import net.minecraftforge.common.MinecraftForge; 19 | import org.lwjgl.input.Keyboard; 20 | import org.lwjgl.opengl.Display; 21 | 22 | import java.io.*; 23 | import java.util.Collections; 24 | 25 | public class PerspectiveMod extends DummyModContainer 26 | { 27 | private static File saveFile; 28 | private static Minecraft mc = Minecraft.getMinecraft(); 29 | private KeyBinding keyPerspective = new KeyBinding("Toggle Perspective", 33, "Perspective Mod"); 30 | 31 | public static boolean returnOnRelease = false; 32 | public static boolean perspectiveToggled = false; 33 | private static float cameraYaw = 0F; 34 | private static float cameraPitch = 0F; 35 | private static int previousPerspective = 0; 36 | 37 | public PerspectiveMod() 38 | { 39 | super(new ModMetadata()); 40 | 41 | // Set mod metadata since modid file will not be read. 42 | ModMetadata meta = getMetadata(); 43 | meta.name = "Perspective Mod 3.0"; 44 | meta.modId = "perspectivemod"; 45 | meta.version = "3.0"; 46 | meta.description = "Allows you to view a full 360 degrees of your character."; 47 | meta.url = "www.youtube.com/canelex"; 48 | meta.authorList = Collections.singletonList("canelex"); 49 | } 50 | 51 | @Override public boolean registerBus(EventBus bus, LoadController controller) 52 | { 53 | // Register this class for FMLInitializationEvent 54 | bus.register(this); 55 | return true; 56 | } 57 | 58 | @Subscribe public void init(FMLInitializationEvent event) 59 | { 60 | // Register forge stuffs 61 | ClientRegistry.registerKeyBinding(keyPerspective); 62 | ClientCommandHandler.instance.registerCommand(new CommandPerspectiveSettings()); 63 | FMLCommonHandler.instance().bus().register(this); 64 | MinecraftForge.EVENT_BUS.register(this); 65 | 66 | // Load settings from binary file. 67 | saveFile = new File(mc.mcDataDir, "perspectivemod-3.0.dat"); 68 | loadSettings(); 69 | } 70 | 71 | @SubscribeEvent public void onKeyPress(InputEvent.KeyInputEvent event) 72 | { 73 | if (Keyboard.getEventKey() == keyPerspective.getKeyCode()) 74 | { 75 | if (Keyboard.getEventKeyState()) 76 | { 77 | perspectiveToggled = !perspectiveToggled; 78 | cameraYaw = mc.thePlayer.rotationYaw; 79 | cameraPitch = mc.thePlayer.rotationPitch; 80 | 81 | if (perspectiveToggled) 82 | { 83 | previousPerspective = mc.gameSettings.thirdPersonView; 84 | mc.gameSettings.thirdPersonView = 1; 85 | } 86 | else 87 | { 88 | mc.gameSettings.thirdPersonView = previousPerspective; 89 | } 90 | } 91 | else if (returnOnRelease) 92 | { 93 | perspectiveToggled = false; 94 | mc.gameSettings.thirdPersonView = previousPerspective; 95 | } 96 | } 97 | 98 | if (Keyboard.getEventKey() == mc.gameSettings.keyBindTogglePerspective.getKeyCode()) 99 | { 100 | perspectiveToggled = false; 101 | } 102 | } 103 | 104 | public static float getCameraYaw() 105 | { 106 | return perspectiveToggled ? cameraYaw : mc.thePlayer.rotationYaw; 107 | } 108 | 109 | public static float getCameraPitch() 110 | { 111 | return perspectiveToggled ? cameraPitch : mc.thePlayer.rotationPitch; 112 | } 113 | 114 | public static boolean overrideMouse() 115 | { 116 | if (mc.inGameHasFocus && Display.isActive()) 117 | { 118 | if (!perspectiveToggled) 119 | { 120 | return true; 121 | } 122 | 123 | // CODE 124 | mc.mouseHelper.mouseXYChange(); 125 | float f1 = mc.gameSettings.mouseSensitivity * 0.6F + 0.2F; 126 | float f2 = f1 * f1 * f1 * 8.0F; 127 | float f3 = (float) mc.mouseHelper.deltaX * f2; 128 | float f4 = (float) mc.mouseHelper.deltaY * f2; 129 | 130 | cameraYaw += f3 * 0.15F; 131 | cameraPitch += f4 * 0.15F; 132 | 133 | if (cameraPitch > 90) cameraPitch = 90; 134 | if (cameraPitch < -90) cameraPitch = -90; 135 | } 136 | 137 | return false; 138 | } 139 | 140 | public static void saveSettings() 141 | { 142 | try 143 | { 144 | BufferedWriter writer = new BufferedWriter(new FileWriter(saveFile)); 145 | writer.write(String.valueOf(returnOnRelease)); 146 | writer.close(); 147 | } catch (Exception ex) 148 | { 149 | System.out.println("Failed to save settings: " + ex.getMessage()); 150 | } 151 | } 152 | 153 | public static void loadSettings() 154 | { 155 | if (!saveFile.exists()) 156 | { 157 | return; 158 | } 159 | 160 | try 161 | { 162 | BufferedReader reader = new BufferedReader(new FileReader(saveFile)); 163 | returnOnRelease = Boolean.parseBoolean(reader.readLine()); 164 | reader.close(); 165 | } catch (Exception ex) 166 | { 167 | System.out.println("Failed to load settings: " + ex.getMessage()); 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/net/canelex/perspectivemod/asm/CameraTransformer.java: -------------------------------------------------------------------------------- 1 | package net.canelex.perspectivemod.asm; 2 | 3 | import net.minecraft.launchwrapper.IClassTransformer; 4 | import org.objectweb.asm.*; 5 | 6 | public class CameraTransformer implements IClassTransformer 7 | { 8 | @Override public byte[] transform(String name, String transformedName, byte[] bytes) 9 | { 10 | if (transformedName.equals("net.minecraft.client.renderer.EntityRenderer")) 11 | { 12 | ClassReader reader = new ClassReader(bytes); 13 | ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 14 | ClassVisitor visitor = new ClassVisitor(Opcodes.ASM4, writer) 15 | { 16 | @Override 17 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] ex) 18 | { 19 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, ex); 20 | 21 | if (desc.equals("(F)V") && name.equals("h") || name.equals("orientCamera")) 22 | { 23 | return new OrientCameraVisitor(mv); 24 | } 25 | 26 | if (desc.equals("(F)V") && name.equals("b") || name.equals("updateCameraAndRender")) 27 | { 28 | return new CameraVisitor(mv); 29 | } 30 | 31 | return mv; 32 | } 33 | }; 34 | 35 | reader.accept(visitor, 0); 36 | return writer.toByteArray(); 37 | } 38 | 39 | return bytes; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/net/canelex/perspectivemod/asm/CameraVisitor.java: -------------------------------------------------------------------------------- 1 | package net.canelex.perspectivemod.asm; 2 | 3 | import org.objectweb.asm.MethodVisitor; 4 | import org.objectweb.asm.Opcodes; 5 | 6 | public class CameraVisitor extends MethodVisitor implements Opcodes 7 | { 8 | public CameraVisitor(MethodVisitor mv) 9 | { 10 | super(ASM4, mv); 11 | } 12 | 13 | @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) 14 | { 15 | if (opcode == GETFIELD && desc.equals("Z") && name.equals("x") || name.equals("inGameHasFocus")) 16 | { 17 | visitMethodInsn(INVOKESTATIC, "net/canelex/perspectivemod/PerspectiveMod", "overrideMouse", "()Z", false); 18 | } 19 | else 20 | { 21 | super.visitFieldInsn(opcode, owner, name, desc); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/net/canelex/perspectivemod/asm/OrientCameraVisitor.java: -------------------------------------------------------------------------------- 1 | package net.canelex.perspectivemod.asm; 2 | 3 | import com.google.common.collect.Maps; 4 | import org.objectweb.asm.MethodVisitor; 5 | import org.objectweb.asm.Opcodes; 6 | 7 | import java.util.HashMap; 8 | 9 | public class OrientCameraVisitor extends MethodVisitor implements Opcodes 10 | { 11 | private HashMap obfList = Maps.newHashMap(); 12 | 13 | public OrientCameraVisitor(MethodVisitor mv) 14 | { 15 | super(ASM4, mv); 16 | 17 | obfList.put("y", "getCameraYaw"); 18 | obfList.put("z", "getCameraPitch"); 19 | obfList.put("A", "getCameraYaw"); 20 | obfList.put("B", "getCameraPitch"); 21 | 22 | // Unobf 23 | obfList.put("rotationYaw", "getCameraYaw"); 24 | obfList.put("rotationPitch", "getCameraPitch"); 25 | obfList.put("prevRotationYaw", "getCameraYaw"); 26 | obfList.put("prevRotationPitch", "getCameraPitch"); 27 | } 28 | 29 | @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) 30 | { 31 | super.visitFieldInsn(opcode, owner, name, desc); 32 | 33 | if (opcode == GETFIELD && desc.equals("F") && owner.equals("sv") || owner.equals("net/minecraft/entity/EntityLivingBase")) 34 | { 35 | if (obfList.containsKey(name)) 36 | { 37 | System.out.println("Replaced " + name + " with " + obfList.get(name)); 38 | visitInsn(FCONST_0); 39 | visitInsn(FMUL); 40 | visitMethodInsn(INVOKESTATIC, "net/canelex/perspectivemod/PerspectiveMod", obfList.get(name), "()F", false); 41 | visitInsn(FADD); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/net/canelex/perspectivemod/command/CommandPerspectiveSettings.java: -------------------------------------------------------------------------------- 1 | package net.canelex.perspectivemod.command; 2 | 3 | import cpw.mods.fml.common.FMLCommonHandler; 4 | import cpw.mods.fml.common.eventhandler.SubscribeEvent; 5 | import cpw.mods.fml.common.gameevent.TickEvent; 6 | import net.canelex.perspectivemod.PerspectiveMod; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.command.CommandBase; 9 | import net.minecraft.command.ICommandSender; 10 | import net.minecraft.util.ChatComponentText; 11 | import net.minecraft.util.EnumChatFormatting; 12 | import org.lwjgl.input.Keyboard; 13 | 14 | public class CommandPerspectiveSettings extends CommandBase 15 | { 16 | @Override public String getCommandName() 17 | { 18 | return "perspectivemod"; 19 | } 20 | 21 | @Override public String getCommandUsage(ICommandSender sender) 22 | { 23 | return "/perspectivemod [hold/press]"; 24 | } 25 | 26 | @Override public boolean canCommandSenderUseCommand(ICommandSender sender) 27 | { 28 | return true; 29 | } 30 | 31 | @Override public void processCommand(ICommandSender sender, String[] args) 32 | { 33 | if (args.length > 0) 34 | { 35 | if (args[0].equalsIgnoreCase("hold")) 36 | { 37 | PerspectiveMod.returnOnRelease = true; 38 | sender.addChatMessage(new ChatComponentText(EnumChatFormatting.LIGHT_PURPLE + "[Perspective Mod] Mode is now 'HOLD_KEY'")); 39 | PerspectiveMod.saveSettings(); 40 | } 41 | else if (args[0].equalsIgnoreCase("press")) 42 | { 43 | PerspectiveMod.returnOnRelease = false; 44 | sender.addChatMessage(new ChatComponentText(EnumChatFormatting.LIGHT_PURPLE + "[Perspective Mod] Mode is now 'PRESS_KEY'")); 45 | PerspectiveMod.saveSettings(); 46 | } 47 | else 48 | { 49 | sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + getCommandUsage(sender))); 50 | } 51 | } 52 | else 53 | { 54 | sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + getCommandUsage(sender))); 55 | } 56 | } 57 | } 58 | --------------------------------------------------------------------------------