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 | + |