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 | 1 | package com.mumfrey.liteloader; |
| 2 | 2 | |
| 3 | +/** | |
| 4 | + * Base interface for mods | |
| 5 | + * | |
| 6 | + * @author Adam Mummery-Smith | |
| 7 | + */ | |
| 3 | 8 | public interface LiteMod |
| 4 | 9 | { |
| 10 | + /** | |
| 11 | + * Get the mod's display name | |
| 12 | + * | |
| 13 | + * @return display name | |
| 14 | + */ | |
| 5 | 15 | public abstract String getName(); |
| 6 | 16 | |
| 17 | + /** | |
| 18 | + * Get the mod version string | |
| 19 | + * | |
| 20 | + * @return | |
| 21 | + */ | |
| 7 | 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 | 28 | public abstract void init(); |
| 10 | 29 | } | ... | ... |
java/com/mumfrey/liteloader/core/HookChat.java
| 1 | 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 | 9 | import net.minecraft.src.NetHandler; |
| 10 | +import net.minecraft.src.Packet; | |
| 4 | 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 | 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 | 48 | public HookChat() |
| 11 | 49 | { |
| 12 | 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 | 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 | 8 | import java.io.IOException; |
| 9 | 9 | import java.io.InputStream; |
| 10 | 10 | import java.io.InputStreamReader; |
| 11 | -import java.lang.reflect.Field; | |
| 11 | +import java.io.PrintWriter; | |
| 12 | +import java.lang.reflect.Constructor; | |
| 12 | 13 | import java.lang.reflect.Method; |
| 13 | -import java.lang.reflect.Modifier; | |
| 14 | 14 | import java.net.URL; |
| 15 | 15 | import java.net.URLClassLoader; |
| 16 | +import java.util.Arrays; | |
| 16 | 17 | import java.util.HashMap; |
| 17 | 18 | import java.util.Iterator; |
| 18 | 19 | import java.util.LinkedList; |
| 19 | -import java.util.Map; | |
| 20 | +import java.util.List; | |
| 20 | 21 | import java.util.logging.ConsoleHandler; |
| 21 | 22 | import java.util.logging.FileHandler; |
| 22 | 23 | import java.util.logging.Formatter; |
| ... | ... | @@ -28,33 +29,39 @@ import java.util.zip.ZipInputStream; |
| 28 | 29 | |
| 29 | 30 | import net.minecraft.client.Minecraft; |
| 30 | 31 | import net.minecraft.src.ConsoleLogManager; |
| 31 | -import net.minecraft.src.IntHashMap; | |
| 32 | 32 | import net.minecraft.src.NetHandler; |
| 33 | -import net.minecraft.src.Packet; | |
| 34 | 33 | import net.minecraft.src.Packet1Login; |
| 35 | 34 | import net.minecraft.src.Packet3Chat; |
| 36 | 35 | import net.minecraft.src.Timer; |
| 37 | 36 | |
| 38 | 37 | import com.mumfrey.liteloader.ChatFilter; |
| 39 | 38 | import com.mumfrey.liteloader.ChatListener; |
| 39 | +import com.mumfrey.liteloader.InitCompleteListener; | |
| 40 | 40 | import com.mumfrey.liteloader.LiteMod; |
| 41 | 41 | import com.mumfrey.liteloader.LoginListener; |
| 42 | 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 | 47 | * LiteLoader is a simple loader which provides tick events to loaded mods |
| 46 | 48 | * |
| 47 | 49 | * @author Adam Mummery-Smith |
| 48 | - * @version 1.3.2_01 | |
| 50 | + * @version 1.3.2_02 | |
| 49 | 51 | */ |
| 50 | 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 | 61 | * against the version.txt value in mod files to prevent outdated mods being |
| 55 | 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 | 67 | * LiteLoader is a singleton, this is the singleton instance |
| ... | ... | @@ -64,7 +71,7 @@ public final class LiteLoader implements FilenameFilter |
| 64 | 71 | /** |
| 65 | 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 | 77 | * "mods" folder which contains mods and config files |
| ... | ... | @@ -90,7 +97,12 @@ public final class LiteLoader implements FilenameFilter |
| 90 | 97 | * List of mods which implement Tickable interface and will receive tick |
| 91 | 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 | 108 | * List of mods which implement ChatListener interface and will receive chat |
| ... | ... | @@ -114,6 +126,8 @@ public final class LiteLoader implements FilenameFilter |
| 114 | 126 | */ |
| 115 | 127 | private Method mAddUrl; |
| 116 | 128 | |
| 129 | + private boolean initDone = false; | |
| 130 | + | |
| 117 | 131 | /** |
| 118 | 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 | 143 | return instance; |
| 130 | 144 | } |
| 131 | 145 | |
| 146 | + public static final Logger getLogger() | |
| 147 | + { | |
| 148 | + return logger; | |
| 149 | + } | |
| 150 | + | |
| 132 | 151 | /** |
| 133 | 152 | * LiteLoader constructor |
| 134 | 153 | */ |
| ... | ... | @@ -137,7 +156,7 @@ public final class LiteLoader implements FilenameFilter |
| 137 | 156 | // Set up loader, initialises any reflection methods needed |
| 138 | 157 | prepareLoader(); |
| 139 | 158 | |
| 140 | - logger.info("Liteloader for " + MINECRAFT_VERSION + " starting up..."); | |
| 159 | + logger.info("Liteloader " + LOADER_VERSION + " starting up..."); | |
| 141 | 160 | |
| 142 | 161 | // Examines the class path and mods folder and locates loadable mods |
| 143 | 162 | prepareMods(); |
| ... | ... | @@ -159,25 +178,37 @@ public final class LiteLoader implements FilenameFilter |
| 159 | 178 | // addURL method is used by the class loader to |
| 160 | 179 | mAddUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); |
| 161 | 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 | 197 | logger.setUseParentHandlers(false); |
| 167 | 198 | |
| 168 | 199 | StreamHandler consoleHandler = new ConsoleHandler(); |
| 169 | - consoleHandler.setFormatter(minecraftLogFormatter); | |
| 200 | + if (minecraftLogFormatter != null) consoleHandler.setFormatter(minecraftLogFormatter); | |
| 170 | 201 | logger.addHandler(consoleHandler); |
| 171 | 202 | |
| 172 | 203 | FileHandler logFileHandler = new FileHandler(new File(Minecraft.getMinecraftDir(), "LiteLoader.txt").getAbsolutePath()); |
| 173 | - logFileHandler.setFormatter(minecraftLogFormatter); | |
| 204 | + if (minecraftLogFormatter != null) logFileHandler.setFormatter(minecraftLogFormatter); | |
| 174 | 205 | logger.addHandler(logFileHandler); |
| 175 | 206 | |
| 176 | 207 | } |
| 177 | 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 | 280 | */ |
| 250 | 281 | protected void findModFiles(File modFolder, LinkedList<File> modFiles) |
| 251 | 282 | { |
| 283 | + List<String> supportedVerions = Arrays.asList(SUPPORTED_VERSIONS); | |
| 284 | + | |
| 252 | 285 | for (File modFile : modFolder.listFiles(this)) |
| 253 | 286 | { |
| 254 | 287 | try |
| ... | ... | @@ -266,7 +299,7 @@ public final class LiteLoader implements FilenameFilter |
| 266 | 299 | versionReader.close(); |
| 267 | 300 | |
| 268 | 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 | 304 | modFiles.add(modFile); |
| 272 | 305 | } |
| ... | ... | @@ -368,7 +401,8 @@ public final class LiteLoader implements FilenameFilter |
| 368 | 401 | } |
| 369 | 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 | 418 | |
| 385 | 419 | try |
| 386 | 420 | { |
| 421 | + logger.info("Initialising mod " + mod.getName() + " version " + mod.getVersion()); | |
| 422 | + | |
| 387 | 423 | mod.init(); |
| 388 | 424 | |
| 389 | 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 | 435 | if (mod instanceof ChatFilter) |
| ... | ... | @@ -408,7 +449,8 @@ public final class LiteLoader implements FilenameFilter |
| 408 | 449 | } |
| 409 | 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 | 454 | iter.remove(); |
| 413 | 455 | } |
| 414 | 456 | } |
| ... | ... | @@ -424,32 +466,24 @@ public final class LiteLoader implements FilenameFilter |
| 424 | 466 | // Chat hook |
| 425 | 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 | 473 | // Login hook |
| 432 | 474 | if (loginListeners.size() > 0) |
| 433 | 475 | { |
| 434 | - registerPacketOverride(1, HookLogin.class); | |
| 476 | + ModUtilities.registerPacketOverride(1, HookLogin.class); | |
| 435 | 477 | HookLogin.loader = this; |
| 436 | 478 | } |
| 437 | 479 | |
| 438 | 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 | 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 | 511 | } |
| 478 | 512 | catch (Throwable th) |
| 479 | 513 | { |
| 480 | - logger.warning(th.getMessage()); | |
| 514 | + logger.warning(th.toString()); | |
| 515 | + th.printStackTrace(); | |
| 481 | 516 | } |
| 482 | 517 | |
| 483 | 518 | return classes; |
| ... | ... | @@ -591,50 +626,12 @@ public final class LiteLoader implements FilenameFilter |
| 591 | 626 | } |
| 592 | 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 | 635 | * Add a URL to the Minecraft classloader class path |
| 639 | 636 | * |
| 640 | 637 | * @param classUrl URL of the resource to add |
| ... | ... | @@ -652,11 +649,36 @@ public final class LiteLoader implements FilenameFilter |
| 652 | 649 | } |
| 653 | 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 | 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 | 684 | * Callback from the tick hook, ticks all tickable mods |
| ... | ... | @@ -670,14 +692,7 @@ public final class LiteLoader implements FilenameFilter |
| 670 | 692 | // Try to get the minecraft timer object and determine the value of the partialTicks |
| 671 | 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 | 697 | // Hooray, we got the timer reference |
| 683 | 698 | if (minecraftTimer != null) |
| ... | ... | @@ -690,7 +705,7 @@ public final class LiteLoader implements FilenameFilter |
| 690 | 705 | boolean inGame = minecraft.renderViewEntity != null && minecraft.renderViewEntity.worldObj != null; |
| 691 | 706 | |
| 692 | 707 | // Iterate tickable mods |
| 693 | - for (Tickable tickable : tickMods) | |
| 708 | + for (Tickable tickable : tickListeners) | |
| 694 | 709 | { |
| 695 | 710 | tickable.onTick(minecraft, partialTicks, inGame, tick); |
| 696 | 711 | } | ... | ... |
java/com/mumfrey/liteloader/core/LiteLoaderHook.java
| 1 | 1 | package com.mumfrey.liteloader.core; |
| 2 | 2 | |
| 3 | +import java.lang.reflect.Field; | |
| 4 | +import java.lang.reflect.Method; | |
| 3 | 5 | import java.util.LinkedList; |
| 4 | 6 | import java.util.logging.Logger; |
| 5 | 7 | |
| 8 | +import net.minecraft.client.Minecraft; | |
| 9 | +import net.minecraft.src.GameSettings; | |
| 6 | 10 | import net.minecraft.src.Profiler; |
| 7 | 11 | |
| 12 | +/** | |
| 13 | + * Main LiteLoader tick hook | |
| 14 | + * | |
| 15 | + * @author Adam Mummery-Smith | |
| 16 | + */ | |
| 8 | 17 | public class LiteLoaderHook extends Profiler |
| 9 | 18 | { |
| 19 | + /** | |
| 20 | + * Logger instance | |
| 21 | + */ | |
| 10 | 22 | private Logger logger; |
| 11 | 23 | |
| 24 | + /** | |
| 25 | + * LiteLoader instance which will receive callbacks | |
| 26 | + */ | |
| 12 | 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 | 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 | 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 | 60 | public LiteLoaderHook(LiteLoader core, Logger logger) |
| 19 | 61 | { |
| 20 | 62 | this.core = core; |
| 21 | 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 | 121 | /* (non-Javadoc) |
| 25 | 122 | * @see net.minecraft.src.Profiler#startSection(java.lang.String) |
| 26 | 123 | */ |
| 27 | 124 | @Override |
| 28 | 125 | public void startSection(String sectionName) |
| 29 | 126 | { |
| 127 | + if (!initDone) | |
| 128 | + { | |
| 129 | + initDone = true; | |
| 130 | + core.onInit(); | |
| 131 | + } | |
| 132 | + | |
| 30 | 133 | if (sectionName.equals("animateTick")) tick = true; |
| 31 | 134 | sections.add(sectionName); |
| 32 | 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 | 154 | /* (non-Javadoc) |
| ... | ... | @@ -39,7 +158,7 @@ public class LiteLoaderHook extends Profiler |
| 39 | 158 | public void endSection() |
| 40 | 159 | { |
| 41 | 160 | super.endSection(); |
| 42 | - | |
| 161 | + | |
| 43 | 162 | String endingSection = sections.removeLast(); |
| 44 | 163 | |
| 45 | 164 | if (endingSection.equalsIgnoreCase("gameRenderer") && sections.getLast().equalsIgnoreCase("root")) |
| ... | ... | @@ -52,5 +171,4 @@ public class LiteLoaderHook extends Profiler |
| 52 | 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 | + | ... | ... |