Commit 71a4ac62e63faeaccb8a86e6dd43a153f6db85e4
1 parent
decde838
Liteloader 1.3.2_02
+ Optifine compatibility + Improved chat hook + Added late init interface + Added ModUtilities class with useful functions in it + Added PrivateFields reflection class from Macros + Improved error message verbosity + Fixed issue with writing server log file to launcher folder
Showing
7 changed files
with
678 additions
and
101 deletions
java/com/mumfrey/liteloader/InitCompleteListener.java
0 → 100644
java/com/mumfrey/liteloader/LiteMod.java
| 1 | package com.mumfrey.liteloader; | 1 | package com.mumfrey.liteloader; |
| 2 | 2 | ||
| 3 | +/** | ||
| 4 | + * Base interface for mods | ||
| 5 | + * | ||
| 6 | + * @author Adam Mummery-Smith | ||
| 7 | + */ | ||
| 3 | public interface LiteMod | 8 | public interface LiteMod |
| 4 | { | 9 | { |
| 10 | + /** | ||
| 11 | + * Get the mod's display name | ||
| 12 | + * | ||
| 13 | + * @return display name | ||
| 14 | + */ | ||
| 5 | public abstract String getName(); | 15 | public abstract String getName(); |
| 6 | 16 | ||
| 17 | + /** | ||
| 18 | + * Get the mod version string | ||
| 19 | + * | ||
| 20 | + * @return | ||
| 21 | + */ | ||
| 7 | public abstract String getVersion(); | 22 | public abstract String getVersion(); |
| 8 | 23 | ||
| 24 | + /** | ||
| 25 | + * Do startup stuff here, minecraft is not fully initialised when this function is called so mods *must not* | ||
| 26 | + * interact with minecraft in any way here | ||
| 27 | + */ | ||
| 9 | public abstract void init(); | 28 | public abstract void init(); |
| 10 | } | 29 | } |
java/com/mumfrey/liteloader/core/HookChat.java
| 1 | package com.mumfrey.liteloader.core; | 1 | package com.mumfrey.liteloader.core; |
| 2 | 2 | ||
| 3 | +import java.io.DataInputStream; | ||
| 4 | +import java.io.DataOutputStream; | ||
| 5 | +import java.io.IOException; | ||
| 6 | +import java.util.Map; | ||
| 7 | + | ||
| 8 | +import net.minecraft.src.IntHashMap; | ||
| 3 | import net.minecraft.src.NetHandler; | 9 | import net.minecraft.src.NetHandler; |
| 10 | +import net.minecraft.src.Packet; | ||
| 4 | import net.minecraft.src.Packet3Chat; | 11 | import net.minecraft.src.Packet3Chat; |
| 5 | 12 | ||
| 13 | +import com.mumfrey.liteloader.util.PrivateFields; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * Proxy packet which we will register in place of the original chat packet. The class will proxy the function calls | ||
| 17 | + * through to the replaced class via reflection if the original (replaced) class is NOT the basic Packet3Chat (this | ||
| 18 | + * is to maintain compatibility with things like WorldEditCUI. | ||
| 19 | + * | ||
| 20 | + * @author Adam Mummery-Smith | ||
| 21 | + * | ||
| 22 | + */ | ||
| 6 | public class HookChat extends Packet3Chat | 23 | public class HookChat extends Packet3Chat |
| 7 | { | 24 | { |
| 8 | - public static LiteLoader loader; | 25 | + /** |
| 26 | + * True if this class was registered with the base class | ||
| 27 | + */ | ||
| 28 | + private static boolean registered = false; | ||
| 9 | 29 | ||
| 30 | + /** | ||
| 31 | + * Handler module which is registered to handle inbound chat packets | ||
| 32 | + */ | ||
| 33 | + private static LiteLoader packetHandler; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * Class which was overridden and will be instanced for new packets | ||
| 37 | + */ | ||
| 38 | + private static Class<? extends Packet> proxyClass; | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * Instance of the proxy packet for this packet instance | ||
| 42 | + */ | ||
| 43 | + private Packet proxyPacket; | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * Create a new chat packet proxy | ||
| 47 | + */ | ||
| 10 | public HookChat() | 48 | public HookChat() |
| 11 | { | 49 | { |
| 12 | super(); | 50 | super(); |
| 51 | + | ||
| 52 | + try | ||
| 53 | + { | ||
| 54 | + if (proxyClass != null) | ||
| 55 | + { | ||
| 56 | + proxyPacket = (Packet)proxyClass.newInstance(); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + catch (Exception ex) {} | ||
| 13 | } | 60 | } |
| 14 | 61 | ||
| 15 | - public HookChat(String par1Str) | 62 | + /** |
| 63 | + * Create a new chat proxy with the specified message | ||
| 64 | + * @param message | ||
| 65 | + */ | ||
| 66 | + public HookChat(String message) | ||
| 16 | { | 67 | { |
| 17 | - super(par1Str); | 68 | + super(message); |
| 69 | + | ||
| 70 | + try | ||
| 71 | + { | ||
| 72 | + if (proxyClass != null) | ||
| 73 | + { | ||
| 74 | + proxyPacket = (Packet)proxyClass.newInstance(); | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + catch (Exception ex) {} | ||
| 18 | } | 78 | } |
| 19 | - | ||
| 20 | - public HookChat(String par1Str, boolean par2) | 79 | + |
| 80 | + @Override | ||
| 81 | + public void readPacketData(DataInputStream datainputstream) throws IOException | ||
| 82 | + { | ||
| 83 | + if (proxyPacket != null) | ||
| 84 | + { | ||
| 85 | + proxyPacket.readPacketData(datainputstream); | ||
| 86 | + this.message = ((Packet3Chat)proxyPacket).message; | ||
| 87 | + } | ||
| 88 | + else | ||
| 89 | + super.readPacketData(datainputstream); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + @Override | ||
| 93 | + public void writePacketData(DataOutputStream dataoutputstream) throws IOException | ||
| 21 | { | 94 | { |
| 22 | - super(par1Str, par2); | 95 | + if (proxyPacket != null) |
| 96 | + proxyPacket.writePacketData(dataoutputstream); | ||
| 97 | + else | ||
| 98 | + super.writePacketData(dataoutputstream); | ||
| 23 | } | 99 | } |
| 24 | 100 | ||
| 25 | - /* (non-Javadoc) | ||
| 26 | - * @see net.minecraft.src.Packet3Chat#processPacket(net.minecraft.src.NetHandler) | ||
| 27 | - */ | ||
| 28 | @Override | 101 | @Override |
| 29 | - public void processPacket(NetHandler par1NetHandler) | 102 | + public void processPacket(NetHandler nethandler) |
| 30 | { | 103 | { |
| 31 | - if (loader == null || loader.onChat(this)) | 104 | + if (packetHandler == null || packetHandler.onChat(this)) |
| 32 | { | 105 | { |
| 33 | - super.processPacket(par1NetHandler); | 106 | + if (proxyPacket != null) |
| 107 | + proxyPacket.processPacket(nethandler); | ||
| 108 | + else | ||
| 109 | + super.processPacket(nethandler); | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + @Override | ||
| 114 | + public int getPacketSize() | ||
| 115 | + { | ||
| 116 | + if (proxyPacket != null) | ||
| 117 | + return proxyPacket.getPacketSize(); | ||
| 118 | + else | ||
| 119 | + return super.getPacketSize(); | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + /** | ||
| 123 | + * Register the specified handler as the packet handler for this packet | ||
| 124 | + * @param handler | ||
| 125 | + */ | ||
| 126 | + public static void RegisterPacketHandler(LiteLoader handler) | ||
| 127 | + { | ||
| 128 | + packetHandler = handler; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + /** | ||
| 132 | + * Register this packet as the new packet for packet ID 3 | ||
| 133 | + */ | ||
| 134 | + public static void Register() | ||
| 135 | + { | ||
| 136 | + Register(false); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + /** | ||
| 140 | + * Register this packet as the new packet for packet ID 3 and optionally force re-registration even | ||
| 141 | + * if registration was performed already. | ||
| 142 | + * | ||
| 143 | + * @param force Force registration even if registration was already performed previously. | ||
| 144 | + */ | ||
| 145 | + public static void Register(boolean force) | ||
| 146 | + { | ||
| 147 | + System.out.println("LITELOADER REGISTER"); | ||
| 148 | + if (!registered || force) | ||
| 149 | + { | ||
| 150 | + try | ||
| 151 | + { | ||
| 152 | + IntHashMap packetIdToClassMap = Packet.packetIdToClassMap; | ||
| 153 | + proxyClass = (Class)packetIdToClassMap.lookup(3); | ||
| 154 | + | ||
| 155 | + if (proxyClass.equals(Packet3Chat.class)) | ||
| 156 | + { | ||
| 157 | + proxyClass = null; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + packetIdToClassMap.removeObject(3); | ||
| 161 | + packetIdToClassMap.addKey(3, HookChat.class); | ||
| 162 | + | ||
| 163 | + Map packetClassToIdMap = PrivateFields.StaticFields.packetClassToIdMap.Get(); | ||
| 164 | + packetClassToIdMap.put(HookChat.class, Integer.valueOf(3)); | ||
| 165 | + | ||
| 166 | + registered = true; | ||
| 167 | + } | ||
| 168 | + catch (Exception ex) | ||
| 169 | + { | ||
| 170 | + ex.printStackTrace(); | ||
| 171 | + } | ||
| 34 | } | 172 | } |
| 35 | } | 173 | } |
| 36 | } | 174 | } |
java/com/mumfrey/liteloader/core/LiteLoader.java
| @@ -8,15 +8,16 @@ import java.io.FilenameFilter; | @@ -8,15 +8,16 @@ import java.io.FilenameFilter; | ||
| 8 | import java.io.IOException; | 8 | import java.io.IOException; |
| 9 | import java.io.InputStream; | 9 | import java.io.InputStream; |
| 10 | import java.io.InputStreamReader; | 10 | import java.io.InputStreamReader; |
| 11 | -import java.lang.reflect.Field; | 11 | +import java.io.PrintWriter; |
| 12 | +import java.lang.reflect.Constructor; | ||
| 12 | import java.lang.reflect.Method; | 13 | import java.lang.reflect.Method; |
| 13 | -import java.lang.reflect.Modifier; | ||
| 14 | import java.net.URL; | 14 | import java.net.URL; |
| 15 | import java.net.URLClassLoader; | 15 | import java.net.URLClassLoader; |
| 16 | +import java.util.Arrays; | ||
| 16 | import java.util.HashMap; | 17 | import java.util.HashMap; |
| 17 | import java.util.Iterator; | 18 | import java.util.Iterator; |
| 18 | import java.util.LinkedList; | 19 | import java.util.LinkedList; |
| 19 | -import java.util.Map; | 20 | +import java.util.List; |
| 20 | import java.util.logging.ConsoleHandler; | 21 | import java.util.logging.ConsoleHandler; |
| 21 | import java.util.logging.FileHandler; | 22 | import java.util.logging.FileHandler; |
| 22 | import java.util.logging.Formatter; | 23 | import java.util.logging.Formatter; |
| @@ -28,33 +29,39 @@ import java.util.zip.ZipInputStream; | @@ -28,33 +29,39 @@ import java.util.zip.ZipInputStream; | ||
| 28 | 29 | ||
| 29 | import net.minecraft.client.Minecraft; | 30 | import net.minecraft.client.Minecraft; |
| 30 | import net.minecraft.src.ConsoleLogManager; | 31 | import net.minecraft.src.ConsoleLogManager; |
| 31 | -import net.minecraft.src.IntHashMap; | ||
| 32 | import net.minecraft.src.NetHandler; | 32 | import net.minecraft.src.NetHandler; |
| 33 | -import net.minecraft.src.Packet; | ||
| 34 | import net.minecraft.src.Packet1Login; | 33 | import net.minecraft.src.Packet1Login; |
| 35 | import net.minecraft.src.Packet3Chat; | 34 | import net.minecraft.src.Packet3Chat; |
| 36 | import net.minecraft.src.Timer; | 35 | import net.minecraft.src.Timer; |
| 37 | 36 | ||
| 38 | import com.mumfrey.liteloader.ChatFilter; | 37 | import com.mumfrey.liteloader.ChatFilter; |
| 39 | import com.mumfrey.liteloader.ChatListener; | 38 | import com.mumfrey.liteloader.ChatListener; |
| 39 | +import com.mumfrey.liteloader.InitCompleteListener; | ||
| 40 | import com.mumfrey.liteloader.LiteMod; | 40 | import com.mumfrey.liteloader.LiteMod; |
| 41 | import com.mumfrey.liteloader.LoginListener; | 41 | import com.mumfrey.liteloader.LoginListener; |
| 42 | import com.mumfrey.liteloader.Tickable; | 42 | import com.mumfrey.liteloader.Tickable; |
| 43 | +import com.mumfrey.liteloader.util.ModUtilities; | ||
| 44 | +import com.mumfrey.liteloader.util.PrivateFields; | ||
| 43 | 45 | ||
| 44 | /** | 46 | /** |
| 45 | * LiteLoader is a simple loader which provides tick events to loaded mods | 47 | * LiteLoader is a simple loader which provides tick events to loaded mods |
| 46 | * | 48 | * |
| 47 | * @author Adam Mummery-Smith | 49 | * @author Adam Mummery-Smith |
| 48 | - * @version 1.3.2_01 | 50 | + * @version 1.3.2_02 |
| 49 | */ | 51 | */ |
| 50 | public final class LiteLoader implements FilenameFilter | 52 | public final class LiteLoader implements FilenameFilter |
| 51 | { | 53 | { |
| 52 | /** | 54 | /** |
| 53 | - * Minecraft version that we will load mods for, this will be compared | 55 | + * Liteloader version |
| 56 | + */ | ||
| 57 | + private static final String LOADER_VERSION = "1.3.2_02"; | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * Minecraft versions that we will load mods for, this will be compared | ||
| 54 | * against the version.txt value in mod files to prevent outdated mods being | 61 | * against the version.txt value in mod files to prevent outdated mods being |
| 55 | * loaded!!! | 62 | * loaded!!! |
| 56 | */ | 63 | */ |
| 57 | - private static final String MINECRAFT_VERSION = "1.3.1"; | 64 | + private static final String[] SUPPORTED_VERSIONS = { "1.3.1", "1.3.2" }; |
| 58 | 65 | ||
| 59 | /** | 66 | /** |
| 60 | * LiteLoader is a singleton, this is the singleton instance | 67 | * LiteLoader is a singleton, this is the singleton instance |
| @@ -64,7 +71,7 @@ public final class LiteLoader implements FilenameFilter | @@ -64,7 +71,7 @@ public final class LiteLoader implements FilenameFilter | ||
| 64 | /** | 71 | /** |
| 65 | * Logger for LiteLoader events | 72 | * Logger for LiteLoader events |
| 66 | */ | 73 | */ |
| 67 | - private static Logger logger = Logger.getLogger("liteloader"); | 74 | + public static Logger logger = Logger.getLogger("liteloader"); |
| 68 | 75 | ||
| 69 | /** | 76 | /** |
| 70 | * "mods" folder which contains mods and config files | 77 | * "mods" folder which contains mods and config files |
| @@ -90,7 +97,12 @@ public final class LiteLoader implements FilenameFilter | @@ -90,7 +97,12 @@ public final class LiteLoader implements FilenameFilter | ||
| 90 | * List of mods which implement Tickable interface and will receive tick | 97 | * List of mods which implement Tickable interface and will receive tick |
| 91 | * events | 98 | * events |
| 92 | */ | 99 | */ |
| 93 | - private LinkedList<Tickable> tickMods = new LinkedList<Tickable>(); | 100 | + private LinkedList<Tickable> tickListeners = new LinkedList<Tickable>(); |
| 101 | + | ||
| 102 | + /** | ||
| 103 | + * | ||
| 104 | + */ | ||
| 105 | + private LinkedList<InitCompleteListener> initListeners = new LinkedList<InitCompleteListener>(); | ||
| 94 | 106 | ||
| 95 | /** | 107 | /** |
| 96 | * List of mods which implement ChatListener interface and will receive chat | 108 | * List of mods which implement ChatListener interface and will receive chat |
| @@ -114,6 +126,8 @@ public final class LiteLoader implements FilenameFilter | @@ -114,6 +126,8 @@ public final class LiteLoader implements FilenameFilter | ||
| 114 | */ | 126 | */ |
| 115 | private Method mAddUrl; | 127 | private Method mAddUrl; |
| 116 | 128 | ||
| 129 | + private boolean initDone = false; | ||
| 130 | + | ||
| 117 | /** | 131 | /** |
| 118 | * Get the singleton instance of LiteLoader, initialises the loader if necessary | 132 | * Get the singleton instance of LiteLoader, initialises the loader if necessary |
| 119 | * | 133 | * |
| @@ -129,6 +143,11 @@ public final class LiteLoader implements FilenameFilter | @@ -129,6 +143,11 @@ public final class LiteLoader implements FilenameFilter | ||
| 129 | return instance; | 143 | return instance; |
| 130 | } | 144 | } |
| 131 | 145 | ||
| 146 | + public static final Logger getLogger() | ||
| 147 | + { | ||
| 148 | + return logger; | ||
| 149 | + } | ||
| 150 | + | ||
| 132 | /** | 151 | /** |
| 133 | * LiteLoader constructor | 152 | * LiteLoader constructor |
| 134 | */ | 153 | */ |
| @@ -137,7 +156,7 @@ public final class LiteLoader implements FilenameFilter | @@ -137,7 +156,7 @@ public final class LiteLoader implements FilenameFilter | ||
| 137 | // Set up loader, initialises any reflection methods needed | 156 | // Set up loader, initialises any reflection methods needed |
| 138 | prepareLoader(); | 157 | prepareLoader(); |
| 139 | 158 | ||
| 140 | - logger.info("Liteloader for " + MINECRAFT_VERSION + " starting up..."); | 159 | + logger.info("Liteloader " + LOADER_VERSION + " starting up..."); |
| 141 | 160 | ||
| 142 | // Examines the class path and mods folder and locates loadable mods | 161 | // Examines the class path and mods folder and locates loadable mods |
| 143 | prepareMods(); | 162 | prepareMods(); |
| @@ -159,25 +178,37 @@ public final class LiteLoader implements FilenameFilter | @@ -159,25 +178,37 @@ public final class LiteLoader implements FilenameFilter | ||
| 159 | // addURL method is used by the class loader to | 178 | // addURL method is used by the class loader to |
| 160 | mAddUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); | 179 | mAddUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); |
| 161 | mAddUrl.setAccessible(true); | 180 | mAddUrl.setAccessible(true); |
| 162 | - | ||
| 163 | - ConsoleLogManager.func_73699_a(); | ||
| 164 | - Formatter minecraftLogFormatter = ConsoleLogManager.loggerLogManager.getHandlers()[0].getFormatter(); | 181 | + |
| 182 | + Formatter minecraftLogFormatter = null; | ||
| 183 | + | ||
| 184 | + try | ||
| 185 | + { | ||
| 186 | + Class formatterClass = Minecraft.class.getClassLoader().loadClass(ModUtilities.getObfuscatedFieldName("net.minecraft.src.ConsoleLogFormatter", "em")); | ||
| 187 | + Constructor defaultConstructor = formatterClass.getDeclaredConstructor(); | ||
| 188 | + defaultConstructor.setAccessible(true); | ||
| 189 | + minecraftLogFormatter = (Formatter)defaultConstructor.newInstance(); | ||
| 190 | + } | ||
| 191 | + catch (Exception ex) | ||
| 192 | + { | ||
| 193 | + ConsoleLogManager.func_73699_a(); | ||
| 194 | + minecraftLogFormatter = ConsoleLogManager.loggerLogManager.getHandlers()[0].getFormatter(); | ||
| 195 | + } | ||
| 165 | 196 | ||
| 166 | logger.setUseParentHandlers(false); | 197 | logger.setUseParentHandlers(false); |
| 167 | 198 | ||
| 168 | StreamHandler consoleHandler = new ConsoleHandler(); | 199 | StreamHandler consoleHandler = new ConsoleHandler(); |
| 169 | - consoleHandler.setFormatter(minecraftLogFormatter); | 200 | + if (minecraftLogFormatter != null) consoleHandler.setFormatter(minecraftLogFormatter); |
| 170 | logger.addHandler(consoleHandler); | 201 | logger.addHandler(consoleHandler); |
| 171 | 202 | ||
| 172 | FileHandler logFileHandler = new FileHandler(new File(Minecraft.getMinecraftDir(), "LiteLoader.txt").getAbsolutePath()); | 203 | FileHandler logFileHandler = new FileHandler(new File(Minecraft.getMinecraftDir(), "LiteLoader.txt").getAbsolutePath()); |
| 173 | - logFileHandler.setFormatter(minecraftLogFormatter); | 204 | + if (minecraftLogFormatter != null) logFileHandler.setFormatter(minecraftLogFormatter); |
| 174 | logger.addHandler(logFileHandler); | 205 | logger.addHandler(logFileHandler); |
| 175 | 206 | ||
| 176 | } | 207 | } |
| 177 | catch (Exception ex) | 208 | catch (Exception ex) |
| 178 | { | 209 | { |
| 179 | - // TODO Auto-generated catch block | ||
| 180 | - ex.printStackTrace(); | 210 | + logger.severe(ex.toString()); |
| 211 | + logger.severe(ex.getStackTrace().toString()); | ||
| 181 | } | 212 | } |
| 182 | 213 | ||
| 183 | } | 214 | } |
| @@ -249,6 +280,8 @@ public final class LiteLoader implements FilenameFilter | @@ -249,6 +280,8 @@ public final class LiteLoader implements FilenameFilter | ||
| 249 | */ | 280 | */ |
| 250 | protected void findModFiles(File modFolder, LinkedList<File> modFiles) | 281 | protected void findModFiles(File modFolder, LinkedList<File> modFiles) |
| 251 | { | 282 | { |
| 283 | + List<String> supportedVerions = Arrays.asList(SUPPORTED_VERSIONS); | ||
| 284 | + | ||
| 252 | for (File modFile : modFolder.listFiles(this)) | 285 | for (File modFile : modFolder.listFiles(this)) |
| 253 | { | 286 | { |
| 254 | try | 287 | try |
| @@ -266,7 +299,7 @@ public final class LiteLoader implements FilenameFilter | @@ -266,7 +299,7 @@ public final class LiteLoader implements FilenameFilter | ||
| 266 | versionReader.close(); | 299 | versionReader.close(); |
| 267 | 300 | ||
| 268 | // Only add the mod if the version matches and we were able to successfully add it to the class path | 301 | // Only add the mod if the version matches and we were able to successfully add it to the class path |
| 269 | - if (strVersion.equals(MINECRAFT_VERSION) && addURLToClassPath(modFile.toURI().toURL())) | 302 | + if (supportedVerions.contains(strVersion) && addURLToClassPath(modFile.toURI().toURL())) |
| 270 | { | 303 | { |
| 271 | modFiles.add(modFile); | 304 | modFiles.add(modFile); |
| 272 | } | 305 | } |
| @@ -368,7 +401,8 @@ public final class LiteLoader implements FilenameFilter | @@ -368,7 +401,8 @@ public final class LiteLoader implements FilenameFilter | ||
| 368 | } | 401 | } |
| 369 | catch (Throwable th) | 402 | catch (Throwable th) |
| 370 | { | 403 | { |
| 371 | - logger.warning(th.getMessage()); | 404 | + logger.warning(th.toString()); |
| 405 | + th.printStackTrace(); | ||
| 372 | } | 406 | } |
| 373 | } | 407 | } |
| 374 | } | 408 | } |
| @@ -384,11 +418,18 @@ public final class LiteLoader implements FilenameFilter | @@ -384,11 +418,18 @@ public final class LiteLoader implements FilenameFilter | ||
| 384 | 418 | ||
| 385 | try | 419 | try |
| 386 | { | 420 | { |
| 421 | + logger.info("Initialising mod " + mod.getName() + " version " + mod.getVersion()); | ||
| 422 | + | ||
| 387 | mod.init(); | 423 | mod.init(); |
| 388 | 424 | ||
| 389 | if (mod instanceof Tickable) | 425 | if (mod instanceof Tickable) |
| 390 | { | 426 | { |
| 391 | - tickMods.add((Tickable)mod); | 427 | + tickListeners.add((Tickable)mod); |
| 428 | + } | ||
| 429 | + | ||
| 430 | + if (mod instanceof InitCompleteListener) | ||
| 431 | + { | ||
| 432 | + initListeners.add((InitCompleteListener)mod); | ||
| 392 | } | 433 | } |
| 393 | 434 | ||
| 394 | if (mod instanceof ChatFilter) | 435 | if (mod instanceof ChatFilter) |
| @@ -408,7 +449,8 @@ public final class LiteLoader implements FilenameFilter | @@ -408,7 +449,8 @@ public final class LiteLoader implements FilenameFilter | ||
| 408 | } | 449 | } |
| 409 | catch (Throwable th) | 450 | catch (Throwable th) |
| 410 | { | 451 | { |
| 411 | - logger.warning("Error initialising mod '" + mod.getName() + "': " + th.getMessage()); | 452 | + logger.warning("Error initialising mod '" + mod.getName() + "': " + th.toString()); |
| 453 | + th.printStackTrace(); | ||
| 412 | iter.remove(); | 454 | iter.remove(); |
| 413 | } | 455 | } |
| 414 | } | 456 | } |
| @@ -424,32 +466,24 @@ public final class LiteLoader implements FilenameFilter | @@ -424,32 +466,24 @@ public final class LiteLoader implements FilenameFilter | ||
| 424 | // Chat hook | 466 | // Chat hook |
| 425 | if (chatListeners.size() > 0 || chatFilters.size() > 0) | 467 | if (chatListeners.size() > 0 || chatFilters.size() > 0) |
| 426 | { | 468 | { |
| 427 | - registerPacketOverride(3, HookChat.class); | ||
| 428 | - HookChat.loader = this; | 469 | + HookChat.Register(); |
| 470 | + HookChat.RegisterPacketHandler(this); | ||
| 429 | } | 471 | } |
| 430 | 472 | ||
| 431 | // Login hook | 473 | // Login hook |
| 432 | if (loginListeners.size() > 0) | 474 | if (loginListeners.size() > 0) |
| 433 | { | 475 | { |
| 434 | - registerPacketOverride(1, HookLogin.class); | 476 | + ModUtilities.registerPacketOverride(1, HookLogin.class); |
| 435 | HookLogin.loader = this; | 477 | HookLogin.loader = this; |
| 436 | } | 478 | } |
| 437 | 479 | ||
| 438 | // Tick hook | 480 | // Tick hook |
| 439 | - if (tickMods.size() > 0) | ||
| 440 | - { | ||
| 441 | - Field modifiers = Field.class.getDeclaredField("modifiers"); | ||
| 442 | - modifiers.setAccessible(true); | ||
| 443 | - | ||
| 444 | - Field profiler = Minecraft.class.getDeclaredField(getObfuscatedFieldName("mcProfiler", "I")); | ||
| 445 | - modifiers.setInt(profiler, profiler.getModifiers() & ~Modifier.FINAL); | ||
| 446 | - profiler.setAccessible(true); | ||
| 447 | - profiler.set(minecraft, new LiteLoaderHook(this, logger)); | ||
| 448 | - } | 481 | + PrivateFields.minecraftProfiler.SetFinal(minecraft, new LiteLoaderHook(this, logger)); |
| 449 | } | 482 | } |
| 450 | catch (Exception ex) | 483 | catch (Exception ex) |
| 451 | { | 484 | { |
| 452 | - logger.warning("Error creating hooks: " + ex.getMessage()); | 485 | + logger.warning("Error creating hooks: " + ex.toString()); |
| 486 | + ex.printStackTrace(); | ||
| 453 | } | 487 | } |
| 454 | } | 488 | } |
| 455 | 489 | ||
| @@ -477,7 +511,8 @@ public final class LiteLoader implements FilenameFilter | @@ -477,7 +511,8 @@ public final class LiteLoader implements FilenameFilter | ||
| 477 | } | 511 | } |
| 478 | catch (Throwable th) | 512 | catch (Throwable th) |
| 479 | { | 513 | { |
| 480 | - logger.warning(th.getMessage()); | 514 | + logger.warning(th.toString()); |
| 515 | + th.printStackTrace(); | ||
| 481 | } | 516 | } |
| 482 | 517 | ||
| 483 | return classes; | 518 | return classes; |
| @@ -591,50 +626,12 @@ public final class LiteLoader implements FilenameFilter | @@ -591,50 +626,12 @@ public final class LiteLoader implements FilenameFilter | ||
| 591 | } | 626 | } |
| 592 | catch (Throwable th) | 627 | catch (Throwable th) |
| 593 | { | 628 | { |
| 594 | - logger.warning(th.getMessage()); | ||
| 595 | - } | ||
| 596 | - } | ||
| 597 | - | ||
| 598 | - /** | ||
| 599 | - * Register a packet override | ||
| 600 | - * | ||
| 601 | - * @param packetId | ||
| 602 | - * @param newPacket | ||
| 603 | - */ | ||
| 604 | - private static boolean registerPacketOverride(int packetId, Class newPacket) | ||
| 605 | - { | ||
| 606 | - try | ||
| 607 | - { | ||
| 608 | - IntHashMap packetIdToClassMap = Packet.packetIdToClassMap; | ||
| 609 | - Field fPacketClassToIdMap = Packet.class.getDeclaredField(getObfuscatedFieldName("packetClassToIdMap", "a")); | ||
| 610 | - fPacketClassToIdMap.setAccessible(true); | ||
| 611 | - Map packetClassToIdMap = (Map)fPacketClassToIdMap.get(null); | ||
| 612 | - | ||
| 613 | - packetIdToClassMap.removeObject(packetId); | ||
| 614 | - packetIdToClassMap.addKey(packetId, newPacket); | ||
| 615 | - packetClassToIdMap.put(newPacket, Integer.valueOf(packetId)); | ||
| 616 | - | ||
| 617 | - return true; | ||
| 618 | - } | ||
| 619 | - catch (Exception ex) | ||
| 620 | - { | ||
| 621 | - logger.warning("Error registering packet override for packet id " + packetId + ": " + ex.getMessage()); | ||
| 622 | - return false; | 629 | + logger.warning(th.toString()); |
| 630 | + th.printStackTrace(); | ||
| 623 | } | 631 | } |
| 624 | } | 632 | } |
| 625 | 633 | ||
| 626 | /** | 634 | /** |
| 627 | - * Abstraction helper function | ||
| 628 | - * | ||
| 629 | - * @param fieldName Name of field to get, returned unmodified if in debug mode | ||
| 630 | - * @return Obfuscated field name if present | ||
| 631 | - */ | ||
| 632 | - private static String getObfuscatedFieldName(String fieldName, String obfuscatedFieldName) | ||
| 633 | - { | ||
| 634 | - return (!net.minecraft.src.Tessellator.instance.getClass().getSimpleName().equals("Tessellator")) ? obfuscatedFieldName : fieldName; | ||
| 635 | - } | ||
| 636 | - | ||
| 637 | - /** | ||
| 638 | * Add a URL to the Minecraft classloader class path | 635 | * Add a URL to the Minecraft classloader class path |
| 639 | * | 636 | * |
| 640 | * @param classUrl URL of the resource to add | 637 | * @param classUrl URL of the resource to add |
| @@ -652,11 +649,36 @@ public final class LiteLoader implements FilenameFilter | @@ -652,11 +649,36 @@ public final class LiteLoader implements FilenameFilter | ||
| 652 | } | 649 | } |
| 653 | catch (Throwable th) | 650 | catch (Throwable th) |
| 654 | { | 651 | { |
| 655 | - logger.warning("Error adding class path entry: " + th.getMessage()); | 652 | + logger.warning("Error adding class path entry: " + th.toString()); |
| 653 | + th.printStackTrace(); | ||
| 656 | } | 654 | } |
| 657 | 655 | ||
| 658 | return false; | 656 | return false; |
| 659 | } | 657 | } |
| 658 | + | ||
| 659 | + /** | ||
| 660 | + * Late initialisation callback | ||
| 661 | + */ | ||
| 662 | + public void onInit() | ||
| 663 | + { | ||
| 664 | + if (!initDone) | ||
| 665 | + { | ||
| 666 | + initDone = true; | ||
| 667 | + | ||
| 668 | + for (InitCompleteListener initMod : initListeners) | ||
| 669 | + { | ||
| 670 | + try | ||
| 671 | + { | ||
| 672 | + logger.info("Calling late init for mod " + initMod.getName()); | ||
| 673 | + initMod.onInitCompleted(minecraft, this); | ||
| 674 | + } | ||
| 675 | + catch (Throwable th) | ||
| 676 | + { | ||
| 677 | + logger.warning("Error initialising mod " + initMod.getName() + ": " + th.getClass().getSimpleName() + " - " + th.getMessage()); | ||
| 678 | + } | ||
| 679 | + } | ||
| 680 | + } | ||
| 681 | + } | ||
| 660 | 682 | ||
| 661 | /** | 683 | /** |
| 662 | * Callback from the tick hook, ticks all tickable mods | 684 | * Callback from the tick hook, ticks all tickable mods |
| @@ -670,14 +692,7 @@ public final class LiteLoader implements FilenameFilter | @@ -670,14 +692,7 @@ public final class LiteLoader implements FilenameFilter | ||
| 670 | // Try to get the minecraft timer object and determine the value of the partialTicks | 692 | // Try to get the minecraft timer object and determine the value of the partialTicks |
| 671 | if (tick || minecraftTimer == null) | 693 | if (tick || minecraftTimer == null) |
| 672 | { | 694 | { |
| 673 | - try | ||
| 674 | - { | ||
| 675 | - Field fTimer = Minecraft.class.getDeclaredField(getObfuscatedFieldName("Timer", "T")); | ||
| 676 | - fTimer.setAccessible(true); | ||
| 677 | - minecraftTimer = (Timer)fTimer.get(minecraft); | ||
| 678 | - | ||
| 679 | - } | ||
| 680 | - catch (Exception ex) {} | 695 | + minecraftTimer = PrivateFields.minecraftTimer.Get(minecraft); |
| 681 | 696 | ||
| 682 | // Hooray, we got the timer reference | 697 | // Hooray, we got the timer reference |
| 683 | if (minecraftTimer != null) | 698 | if (minecraftTimer != null) |
| @@ -690,7 +705,7 @@ public final class LiteLoader implements FilenameFilter | @@ -690,7 +705,7 @@ public final class LiteLoader implements FilenameFilter | ||
| 690 | boolean inGame = minecraft.renderViewEntity != null && minecraft.renderViewEntity.worldObj != null; | 705 | boolean inGame = minecraft.renderViewEntity != null && minecraft.renderViewEntity.worldObj != null; |
| 691 | 706 | ||
| 692 | // Iterate tickable mods | 707 | // Iterate tickable mods |
| 693 | - for (Tickable tickable : tickMods) | 708 | + for (Tickable tickable : tickListeners) |
| 694 | { | 709 | { |
| 695 | tickable.onTick(minecraft, partialTicks, inGame, tick); | 710 | tickable.onTick(minecraft, partialTicks, inGame, tick); |
| 696 | } | 711 | } |
java/com/mumfrey/liteloader/core/LiteLoaderHook.java
| 1 | package com.mumfrey.liteloader.core; | 1 | package com.mumfrey.liteloader.core; |
| 2 | 2 | ||
| 3 | +import java.lang.reflect.Field; | ||
| 4 | +import java.lang.reflect.Method; | ||
| 3 | import java.util.LinkedList; | 5 | import java.util.LinkedList; |
| 4 | import java.util.logging.Logger; | 6 | import java.util.logging.Logger; |
| 5 | 7 | ||
| 8 | +import net.minecraft.client.Minecraft; | ||
| 9 | +import net.minecraft.src.GameSettings; | ||
| 6 | import net.minecraft.src.Profiler; | 10 | import net.minecraft.src.Profiler; |
| 7 | 11 | ||
| 12 | +/** | ||
| 13 | + * Main LiteLoader tick hook | ||
| 14 | + * | ||
| 15 | + * @author Adam Mummery-Smith | ||
| 16 | + */ | ||
| 8 | public class LiteLoaderHook extends Profiler | 17 | public class LiteLoaderHook extends Profiler |
| 9 | { | 18 | { |
| 19 | + /** | ||
| 20 | + * Logger instance | ||
| 21 | + */ | ||
| 10 | private Logger logger; | 22 | private Logger logger; |
| 11 | 23 | ||
| 24 | + /** | ||
| 25 | + * LiteLoader instance which will receive callbacks | ||
| 26 | + */ | ||
| 12 | private LiteLoader core; | 27 | private LiteLoader core; |
| 13 | 28 | ||
| 29 | + /** | ||
| 30 | + * Section list, used as a kind of stack to determine where we are in the profiler stack | ||
| 31 | + */ | ||
| 14 | private LinkedList<String> sections = new LinkedList<String>(); | 32 | private LinkedList<String> sections = new LinkedList<String>(); |
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * Initialisation done | ||
| 36 | + */ | ||
| 37 | + private boolean initDone = false; | ||
| 15 | 38 | ||
| 39 | + /** | ||
| 40 | + * Tick clock, sent as a flag to the core onTick so that mods know it's a new tick | ||
| 41 | + */ | ||
| 16 | private boolean tick; | 42 | private boolean tick; |
| 17 | 43 | ||
| 44 | + /** | ||
| 45 | + * Optifine compatibility, pointer to the "Profiler" setting so we can enable it if it's disabled | ||
| 46 | + */ | ||
| 47 | + private Field ofProfiler; | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * Minecraft reference, only set if optifine compatibility is enabled | ||
| 51 | + */ | ||
| 52 | + private Minecraft mc; | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * .ctor | ||
| 56 | + * | ||
| 57 | + * @param core LiteLoader object which will get callbacks | ||
| 58 | + * @param logger Logger instance | ||
| 59 | + */ | ||
| 18 | public LiteLoaderHook(LiteLoader core, Logger logger) | 60 | public LiteLoaderHook(LiteLoader core, Logger logger) |
| 19 | { | 61 | { |
| 20 | this.core = core; | 62 | this.core = core; |
| 21 | this.logger = logger; | 63 | this.logger = logger; |
| 64 | + | ||
| 65 | + // Detect optifine (duh!) | ||
| 66 | + DetectOptifine(); | ||
| 22 | } | 67 | } |
| 23 | 68 | ||
| 69 | + /** | ||
| 70 | + * Try to detect optifine using reflection | ||
| 71 | + * | ||
| 72 | + * @param logger | ||
| 73 | + */ | ||
| 74 | + private void DetectOptifine() | ||
| 75 | + { | ||
| 76 | + try | ||
| 77 | + { | ||
| 78 | + ofProfiler = GameSettings.class.getDeclaredField("ofProfiler"); | ||
| 79 | + } | ||
| 80 | + catch (SecurityException ex) {} | ||
| 81 | + catch (NoSuchFieldException ex) | ||
| 82 | + { | ||
| 83 | + logger.info("Optifine not detected"); | ||
| 84 | + } | ||
| 85 | + finally | ||
| 86 | + { | ||
| 87 | + if (ofProfiler != null) | ||
| 88 | + { | ||
| 89 | + logger.info(String.format("Optifine version %s detected, enabling compatibility check", GetOptifineVersion())); | ||
| 90 | + mc = Minecraft.getMinecraft(); | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + /** | ||
| 96 | + * Try to get the optifine version using reflection | ||
| 97 | + * | ||
| 98 | + * @return | ||
| 99 | + */ | ||
| 100 | + private String GetOptifineVersion() | ||
| 101 | + { | ||
| 102 | + try | ||
| 103 | + { | ||
| 104 | + Class config = Class.forName("Config"); | ||
| 105 | + | ||
| 106 | + if (config != null) | ||
| 107 | + { | ||
| 108 | + Method getVersion = config.getDeclaredMethod("getVersion"); | ||
| 109 | + | ||
| 110 | + if (getVersion != null) | ||
| 111 | + { | ||
| 112 | + return (String)getVersion.invoke(null); | ||
| 113 | + } | ||
| 114 | + } | ||
| 115 | + } | ||
| 116 | + catch (Exception ex) {} | ||
| 117 | + | ||
| 118 | + return "Unknown"; | ||
| 119 | + } | ||
| 120 | + | ||
| 24 | /* (non-Javadoc) | 121 | /* (non-Javadoc) |
| 25 | * @see net.minecraft.src.Profiler#startSection(java.lang.String) | 122 | * @see net.minecraft.src.Profiler#startSection(java.lang.String) |
| 26 | */ | 123 | */ |
| 27 | @Override | 124 | @Override |
| 28 | public void startSection(String sectionName) | 125 | public void startSection(String sectionName) |
| 29 | { | 126 | { |
| 127 | + if (!initDone) | ||
| 128 | + { | ||
| 129 | + initDone = true; | ||
| 130 | + core.onInit(); | ||
| 131 | + } | ||
| 132 | + | ||
| 30 | if (sectionName.equals("animateTick")) tick = true; | 133 | if (sectionName.equals("animateTick")) tick = true; |
| 31 | sections.add(sectionName); | 134 | sections.add(sectionName); |
| 32 | super.startSection(sectionName); | 135 | super.startSection(sectionName); |
| 136 | + | ||
| 137 | + if (ofProfiler != null) | ||
| 138 | + { | ||
| 139 | + try | ||
| 140 | + { | ||
| 141 | + ofProfiler.set(mc.gameSettings, true); | ||
| 142 | + } | ||
| 143 | + catch (IllegalArgumentException ex) | ||
| 144 | + { | ||
| 145 | + ofProfiler = null; | ||
| 146 | + } | ||
| 147 | + catch (IllegalAccessException ex) | ||
| 148 | + { | ||
| 149 | + ofProfiler = null; | ||
| 150 | + } | ||
| 151 | + } | ||
| 33 | } | 152 | } |
| 34 | 153 | ||
| 35 | /* (non-Javadoc) | 154 | /* (non-Javadoc) |
| @@ -39,7 +158,7 @@ public class LiteLoaderHook extends Profiler | @@ -39,7 +158,7 @@ public class LiteLoaderHook extends Profiler | ||
| 39 | public void endSection() | 158 | public void endSection() |
| 40 | { | 159 | { |
| 41 | super.endSection(); | 160 | super.endSection(); |
| 42 | - | 161 | + |
| 43 | String endingSection = sections.removeLast(); | 162 | String endingSection = sections.removeLast(); |
| 44 | 163 | ||
| 45 | if (endingSection.equalsIgnoreCase("gameRenderer") && sections.getLast().equalsIgnoreCase("root")) | 164 | if (endingSection.equalsIgnoreCase("gameRenderer") && sections.getLast().equalsIgnoreCase("root")) |
| @@ -52,5 +171,4 @@ public class LiteLoaderHook extends Profiler | @@ -52,5 +171,4 @@ public class LiteLoaderHook extends Profiler | ||
| 52 | super.endSection(); | 171 | super.endSection(); |
| 53 | } | 172 | } |
| 54 | } | 173 | } |
| 55 | - | ||
| 56 | } | 174 | } |
java/com/mumfrey/liteloader/util/ModUtilities.java
0 → 100644
| 1 | +package com.mumfrey.liteloader.util; | ||
| 2 | + | ||
| 3 | +import java.lang.reflect.Field; | ||
| 4 | +import java.util.Arrays; | ||
| 5 | +import java.util.LinkedList; | ||
| 6 | +import java.util.Map; | ||
| 7 | + | ||
| 8 | +import net.minecraft.client.Minecraft; | ||
| 9 | +import net.minecraft.src.IntHashMap; | ||
| 10 | +import net.minecraft.src.KeyBinding; | ||
| 11 | +import net.minecraft.src.Packet; | ||
| 12 | +import net.minecraft.src.Render; | ||
| 13 | +import net.minecraft.src.RenderManager; | ||
| 14 | +import net.minecraft.src.Tessellator; | ||
| 15 | + | ||
| 16 | +import com.mumfrey.liteloader.core.LiteLoader; | ||
| 17 | + | ||
| 18 | +public abstract class ModUtilities | ||
| 19 | +{ | ||
| 20 | + /** | ||
| 21 | + * Add a renderer map entry for the specified entity class | ||
| 22 | + * | ||
| 23 | + * @param entityClass | ||
| 24 | + * @param renderer | ||
| 25 | + */ | ||
| 26 | + public static void addRenderer(Class entityClass, Render renderer) | ||
| 27 | + { | ||
| 28 | + Map entityRenderMap = PrivateFields.entityRenderMap.Get(RenderManager.instance); | ||
| 29 | + entityRenderMap.put(entityClass, renderer); | ||
| 30 | + renderer.setRenderManager(RenderManager.instance); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * Register a packet override | ||
| 35 | + * | ||
| 36 | + * @param packetId | ||
| 37 | + * @param newPacket | ||
| 38 | + */ | ||
| 39 | + public static boolean registerPacketOverride(int packetId, Class newPacket) | ||
| 40 | + { | ||
| 41 | + try | ||
| 42 | + { | ||
| 43 | + IntHashMap packetIdToClassMap = Packet.packetIdToClassMap; | ||
| 44 | + PrivateFields.StaticFields.packetClassToIdMap.Get(); | ||
| 45 | + Map packetClassToIdMap = PrivateFields.StaticFields.packetClassToIdMap.Get(); | ||
| 46 | + | ||
| 47 | + packetIdToClassMap.removeObject(packetId); | ||
| 48 | + packetIdToClassMap.addKey(packetId, newPacket); | ||
| 49 | + packetClassToIdMap.put(newPacket, Integer.valueOf(packetId)); | ||
| 50 | + | ||
| 51 | + return true; | ||
| 52 | + } | ||
| 53 | + catch (Exception ex) | ||
| 54 | + { | ||
| 55 | + LiteLoader.logger.warning("Error registering packet override for packet id " + packetId + ": " + ex.getMessage()); | ||
| 56 | + return false; | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * Abstraction helper function | ||
| 62 | + * | ||
| 63 | + * @param fieldName Name of field to get, returned unmodified if in debug mode | ||
| 64 | + * @return Obfuscated field name if present | ||
| 65 | + */ | ||
| 66 | + public static String getObfuscatedFieldName(String fieldName, String obfuscatedFieldName) | ||
| 67 | + { | ||
| 68 | + return (!net.minecraft.src.Tessellator.instance.getClass().getSimpleName().equals("Tessellator")) ? obfuscatedFieldName : fieldName; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * Registers a keybind with the game settings class so that it is configurable in the "controls" screen | ||
| 73 | + * | ||
| 74 | + * @param newBinding key binding to add | ||
| 75 | + */ | ||
| 76 | + public static void registerKey(KeyBinding newBinding) | ||
| 77 | + { | ||
| 78 | + Minecraft mc = Minecraft.getMinecraft(); | ||
| 79 | + | ||
| 80 | + if (mc == null || mc.gameSettings == null) return; | ||
| 81 | + | ||
| 82 | + LinkedList<KeyBinding> keyBindings = new LinkedList<KeyBinding>(); | ||
| 83 | + keyBindings.addAll(Arrays.asList(mc.gameSettings.keyBindings)); | ||
| 84 | + | ||
| 85 | + if (!keyBindings.contains(newBinding)) | ||
| 86 | + { | ||
| 87 | + keyBindings.add(newBinding); | ||
| 88 | + mc.gameSettings.keyBindings = keyBindings.toArray(new KeyBinding[0]); | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + /** | ||
| 93 | + * Unregisters a registered keybind with the game settings class, thus removing it from the "controls" screen | ||
| 94 | + * | ||
| 95 | + * @param removeBinding | ||
| 96 | + */ | ||
| 97 | + public static void unRegisterKey(KeyBinding removeBinding) | ||
| 98 | + { | ||
| 99 | + Minecraft mc = Minecraft.getMinecraft(); | ||
| 100 | + | ||
| 101 | + if (mc == null || mc.gameSettings == null) return; | ||
| 102 | + | ||
| 103 | + LinkedList<KeyBinding> keyBindings = new LinkedList<KeyBinding>(); | ||
| 104 | + keyBindings.addAll(Arrays.asList(mc.gameSettings.keyBindings)); | ||
| 105 | + | ||
| 106 | + if (keyBindings.contains(removeBinding)) | ||
| 107 | + { | ||
| 108 | + keyBindings.remove(removeBinding); | ||
| 109 | + mc.gameSettings.keyBindings = keyBindings.toArray(new KeyBinding[0]); | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | +} |
java/com/mumfrey/liteloader/util/PrivateFields.java
0 → 100644
| 1 | +package com.mumfrey.liteloader.util; | ||
| 2 | + | ||
| 3 | +import java.io.File; | ||
| 4 | +import java.lang.reflect.Field; | ||
| 5 | +import java.lang.reflect.Modifier; | ||
| 6 | +import java.util.Map; | ||
| 7 | +import java.util.Properties; | ||
| 8 | +import java.util.zip.ZipFile; | ||
| 9 | + | ||
| 10 | +import net.minecraft.client.Minecraft; | ||
| 11 | +import net.minecraft.src.GuiButton; | ||
| 12 | +import net.minecraft.src.GuiIngame; | ||
| 13 | +import net.minecraft.src.GuiScreen; | ||
| 14 | +import net.minecraft.src.GuiSlot; | ||
| 15 | +import net.minecraft.src.GuiTexturePacks; | ||
| 16 | +import net.minecraft.src.NetClientHandler; | ||
| 17 | +import net.minecraft.src.NetworkManager; | ||
| 18 | +import net.minecraft.src.Packet; | ||
| 19 | +import net.minecraft.src.Profiler; | ||
| 20 | +import net.minecraft.src.RenderEngine; | ||
| 21 | +import net.minecraft.src.RenderGlobal; | ||
| 22 | +import net.minecraft.src.RenderManager; | ||
| 23 | +import net.minecraft.src.SoundManager; | ||
| 24 | +import net.minecraft.src.SoundPool; | ||
| 25 | +import net.minecraft.src.StringTranslate; | ||
| 26 | +import net.minecraft.src.TexturePackCustom; | ||
| 27 | +import net.minecraft.src.TexturePackImplementation; | ||
| 28 | +import net.minecraft.src.TexturePackList; | ||
| 29 | +import net.minecraft.src.TileEntity; | ||
| 30 | +import net.minecraft.src.Timer; | ||
| 31 | +import net.minecraft.src.WorldInfo; | ||
| 32 | +import net.minecraft.src.WorldRenderer; | ||
| 33 | +import net.minecraft.src.WorldType; | ||
| 34 | + | ||
| 35 | +/** | ||
| 36 | + * Wrapper for obf/mcp reflection-accessed private fields, mainly added to centralise the locations I have to update the obfuscated field names | ||
| 37 | + * | ||
| 38 | + * @author Adam Mummery-Smith | ||
| 39 | + * | ||
| 40 | + * @param <P> Parent class type, the type of the class that owns the field | ||
| 41 | + * @param <T> Field type, the type of the field value | ||
| 42 | + */ | ||
| 43 | +public class PrivateFields<P, T> | ||
| 44 | +{ | ||
| 45 | + /** | ||
| 46 | + * Class to which this field belongs | ||
| 47 | + */ | ||
| 48 | + public final Class parentClass; | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * MCP name for this field | ||
| 52 | + */ | ||
| 53 | + public final String mcpName; | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * Real (obfuscated) name for this field | ||
| 57 | + */ | ||
| 58 | + public final String name; | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * Name used to access the field, determined at init | ||
| 62 | + */ | ||
| 63 | + private final String fieldName; | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Creates a new private field entry | ||
| 67 | + * | ||
| 68 | + * @param owner | ||
| 69 | + * @param mcpName | ||
| 70 | + * @param name | ||
| 71 | + */ | ||
| 72 | + private PrivateFields(Class owner, String mcpName, String name) | ||
| 73 | + { | ||
| 74 | + this.parentClass = owner; | ||
| 75 | + this.mcpName = mcpName; | ||
| 76 | + this.name = name; | ||
| 77 | + | ||
| 78 | + this.fieldName = ModUtilities.getObfuscatedFieldName(mcpName, name); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + /** | ||
| 82 | + * Get the current value of this field on the instance class supplied | ||
| 83 | + * | ||
| 84 | + * @param instance Class to get the value of | ||
| 85 | + * @return field value or null if errors occur | ||
| 86 | + */ | ||
| 87 | + public T Get(P instance) | ||
| 88 | + { | ||
| 89 | + try | ||
| 90 | + { | ||
| 91 | + Field field = parentClass.getDeclaredField(fieldName); | ||
| 92 | + field.setAccessible(true); | ||
| 93 | + return (T)field.get(instance); | ||
| 94 | + } | ||
| 95 | + catch (Exception ex) | ||
| 96 | + { | ||
| 97 | + return null; | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + /** | ||
| 102 | + * Set the value of this field on the instance class supplied | ||
| 103 | + * | ||
| 104 | + * @param instance Object to set the value of the field on | ||
| 105 | + * @param value value to set | ||
| 106 | + * @return value | ||
| 107 | + */ | ||
| 108 | + public T Set(P instance, T value) | ||
| 109 | + { | ||
| 110 | + try | ||
| 111 | + { | ||
| 112 | + Field field = parentClass.getDeclaredField(fieldName); | ||
| 113 | + field.setAccessible(true); | ||
| 114 | + field.set(instance, value); | ||
| 115 | + } | ||
| 116 | + catch (Exception ex) {} | ||
| 117 | + | ||
| 118 | + return value; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + /** | ||
| 122 | + * Set the value of this FINAL field on the instance class supplied | ||
| 123 | + * | ||
| 124 | + * @param instance Object to set the value of the field on | ||
| 125 | + * @param value value to set | ||
| 126 | + * @return value | ||
| 127 | + */ | ||
| 128 | + public T SetFinal(P instance, T value) | ||
| 129 | + { | ||
| 130 | + try | ||
| 131 | + { | ||
| 132 | + Field modifiers = Field.class.getDeclaredField("modifiers"); | ||
| 133 | + modifiers.setAccessible(true); | ||
| 134 | + | ||
| 135 | + Field field = parentClass.getDeclaredField(fieldName); | ||
| 136 | + modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL); | ||
| 137 | + field.setAccessible(true); | ||
| 138 | + field.set(instance, value); | ||
| 139 | + } | ||
| 140 | + catch (Exception ex) {} | ||
| 141 | + | ||
| 142 | + return value; | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + /** | ||
| 146 | + * Static private fields | ||
| 147 | + * | ||
| 148 | + * @param <P> Parent class type, the type of the class that owns the field | ||
| 149 | + * @param <T> Field type, the type of the field value | ||
| 150 | + */ | ||
| 151 | + public static final class StaticFields<P, T> extends PrivateFields<P, T> | ||
| 152 | + { | ||
| 153 | + public StaticFields(Class owner, String mcpName, String name) { super(owner, mcpName, name); } | ||
| 154 | + public T Get() { return Get(null); } | ||
| 155 | + public void Set(T value) { Set(null, value); } | ||
| 156 | + | ||
| 157 | + public static final StaticFields<Packet, Map> packetClassToIdMap = new StaticFields<Packet, Map> (Packet.class, "packetClassToIdMap", "a"); | ||
| 158 | + public static final StaticFields<TileEntity, Map> tileEntityNameToClassMap = new StaticFields<TileEntity, Map> (TileEntity.class, "nameToClassMap", "a"); | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + public static final PrivateFields<Minecraft, Timer> minecraftTimer = new PrivateFields<Minecraft, Timer> (Minecraft.class, "timer", "T"); | ||
| 162 | + public static final PrivateFields<RenderManager, Map> entityRenderMap = new PrivateFields<RenderManager, Map> (RenderManager.class, "entityRenderMap", "o"); | ||
| 163 | + public static final PrivateFields<Minecraft, Profiler> minecraftProfiler = new PrivateFields<Minecraft, Profiler> (Minecraft.class, "mcProfiler", "I"); | ||
| 164 | +} | ||
| 165 | + |