├── .gitignore ├── .idea ├── .gitignore ├── artifacts │ └── InjectionClientTest_jar.xml ├── compiler.xml ├── discord.xml ├── jarRepositories.xml ├── misc.xml └── uiDesigner.xml ├── README.md ├── pom.xml └── src ├── main ├── java │ ├── com │ │ └── darkmagician6 │ │ │ └── eventapi │ │ │ ├── EventAPI.java │ │ │ ├── EventManager.java │ │ │ ├── EventTarget.java │ │ │ ├── events │ │ │ ├── Cancellable.java │ │ │ ├── Event.java │ │ │ ├── EventStoppable.java │ │ │ ├── Typed.java │ │ │ └── callables │ │ │ │ ├── EventCancellable.java │ │ │ │ └── EventTyped.java │ │ │ └── types │ │ │ ├── EventType.java │ │ │ └── Priority.java │ └── me │ │ └── dickmeister │ │ ├── agent │ │ ├── ClientAgent.java │ │ ├── attacher │ │ │ └── AgentAttacher.java │ │ └── modules │ │ │ ├── AgentModule.java │ │ │ └── impl │ │ │ ├── MinecraftJarInjectorModule.java │ │ │ ├── MinecraftQueueFinderModule.java │ │ │ ├── VersionFinderModule.java │ │ │ └── VersionMappingDownloaderModule.java │ │ ├── client │ │ ├── ClientMain.java │ │ ├── core │ │ │ ├── command │ │ │ │ ├── Command.java │ │ │ │ ├── CommandManager.java │ │ │ │ └── impl │ │ │ │ │ ├── HelpCommand.java │ │ │ │ │ ├── HitboxCommand.java │ │ │ │ │ ├── PanicCommand.java │ │ │ │ │ └── ToggleCommand.java │ │ │ ├── event │ │ │ │ ├── EventDistributor.java │ │ │ │ ├── EventInjector.java │ │ │ │ ├── impl │ │ │ │ │ ├── ClientInternalTickEvent.java │ │ │ │ │ ├── KeyPressEvent.java │ │ │ │ │ ├── PlayerChatEvent.java │ │ │ │ │ └── Render2DEvent.java │ │ │ │ └── util │ │ │ │ │ ├── EventCaller.java │ │ │ │ │ └── EventInitializer.java │ │ │ ├── gui │ │ │ │ └── GuiIngameRenderer.java │ │ │ ├── module │ │ │ │ ├── Module.java │ │ │ │ ├── ModuleCategory.java │ │ │ │ ├── ModuleManager.java │ │ │ │ └── impl │ │ │ │ │ ├── combat │ │ │ │ │ └── HitboxModule.java │ │ │ │ │ └── render │ │ │ │ │ └── ESPModule.java │ │ │ └── utils │ │ │ │ └── minecraft │ │ │ │ ├── MinecraftUtil.java │ │ │ │ └── impl │ │ │ │ └── MinecraftUtil_118x.java │ │ ├── mappings │ │ │ ├── MappingManager.java │ │ │ ├── VersionMappingsLoader.java │ │ │ ├── loader │ │ │ │ └── MappingsLoader.java │ │ │ └── proguard │ │ │ │ ├── MappingReader.java │ │ │ │ ├── objects │ │ │ │ ├── MappedClass.java │ │ │ │ ├── MappedField.java │ │ │ │ └── MappedMethod.java │ │ │ │ ├── processor │ │ │ │ ├── MappingProcessor.java │ │ │ │ └── impl │ │ │ │ │ └── ClientMappingProcessor.java │ │ │ │ └── utils │ │ │ │ └── ProguardMap.java │ │ ├── tasks │ │ │ └── TickingTask.java │ │ ├── transformers │ │ │ └── TestTransformer.java │ │ └── version │ │ │ ├── VersionFinder.java │ │ │ └── component │ │ │ ├── VersionFinderComponent.java │ │ │ └── impl │ │ │ └── LatestFinderComponent.java │ │ ├── common │ │ └── util │ │ │ ├── LogUtil.java │ │ │ └── URLUtils.java │ │ └── injector │ │ └── ClientInjector.java └── resources │ └── META-INF │ └── MANIFEST.MF └── test └── java ├── AttachTest.java └── MappingPrinter.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /out/ 3 | /target/ -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/artifacts/InjectionClientTest_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/InjectionClientTest_jar 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/discord.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InjectionClient 2 | 3 | This project was used to learn injecting a "working" hacked client into minecraft 4 | 5 | ### Requires to run client from the JDK, set your jdk 17 as runtime for minecraft client, idk if it requires it or not just use it to be safe. 6 | ### Only supports 1.18 vanilla version of the game, but feel free to push your changes regarding compatibility 7 | 8 | # Working modules 9 | - ESP (Click "O" when injected) 10 | - Hitbox (Click "K" when injected - it is bugged af causes movement problems) 11 | 12 | # Commands 13 | - ,help - Sends command list 14 | - ,hitbox - lets you set the hitbox width and height 15 | - ,toggle - toggles a module 16 | - ,panic - disabling client 17 | 18 | # How to run 19 | - Compile the project into jar file including all dependencies 20 | - Run your minecraft client (1.18 vanilla only supported) 21 | - Run the jar file using java -jar (jdk 17 or newer) 22 | - Select your minecraft client in the list that was displayed, enter a number containing "net.minecraft.client.main.Main" and click enter 23 | - After 3 - 5 seconds you should see a "InjectClient v0" text in the left upper corner of the game 24 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | InjectionClientTest 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | com.google.code.gson 14 | gson 15 | 2.9.0 16 | 17 | 18 | net.bytebuddy 19 | byte-buddy 20 | LATEST 21 | 22 | 23 | net.bytebuddy 24 | byte-buddy-agent 25 | 1.12.10 26 | 27 | 28 | org.reflections 29 | reflections 30 | 0.10.2 31 | 32 | 33 | javassist 34 | javassist 35 | 3.12.1.GA 36 | 37 | 38 | 39 | 40 | 17 41 | 17 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/EventAPI.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This is an API used for handling events across your java based projects. 3 | * It's meant to be simple to use without sacrificing performance and extensibility. 4 | * 5 | * Currently the API is in beta phase but it's stable and ready to be used. 6 | * 7 | * If you have any suggestion for improvements/fixes for shit, 8 | * feel free to make a pull request on the bitbucket: https://bitbucket.org/DarkMagician6/eventapi/overview. 9 | * 10 | * For information on how to use the API take a look at the wiki: 11 | * https://bitbucket.org/DarkMagician6/eventapi/wiki/Home 12 | * 13 | * @Todo Improve/update the wiki. 14 | */ 15 | package com.darkmagician6.eventapi; 16 | 17 | /** 18 | * Main class for the API. 19 | * Contains various information about the API. 20 | * 21 | * @author DarkMagician6 22 | * @since July 31, 2013 23 | */ 24 | public final class EventAPI { 25 | 26 | /** 27 | * No need to create an Object of this class as all Methods are static. 28 | */ 29 | private EventAPI() { 30 | } 31 | 32 | /** 33 | * The current version of the API. 34 | */ 35 | public static final String VERSION = String.format("%s-%s", "0.7", "beta"); 36 | 37 | /** 38 | * Array containing the authors of the API. 39 | */ 40 | public static final String[] AUTHORS = { 41 | "DarkMagician6" 42 | }; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/EventManager.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | import java.util.HashMap; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.concurrent.CopyOnWriteArrayList; 10 | 11 | import com.darkmagician6.eventapi.events.Event; 12 | import com.darkmagician6.eventapi.events.EventStoppable; 13 | import com.darkmagician6.eventapi.types.Priority; 14 | 15 | /** 16 | * 17 | * 18 | * @author DarkMagician6 19 | * @since February 2, 2014 20 | */ 21 | public final class EventManager { 22 | 23 | /** 24 | * HashMap containing all the registered MethodData sorted on the event parameters of the methods. 25 | */ 26 | private static final Map, List> REGISTRY_MAP = new HashMap, List>(); 27 | 28 | /** 29 | * All methods in this class are static so there would be no reason to create an object of the EventManager class. 30 | */ 31 | private EventManager() { 32 | } 33 | 34 | /** 35 | * Registers all the methods marked with the EventTarget annotation in the class of the given Object. 36 | * 37 | * @param object 38 | * Object that you want to register. 39 | */ 40 | public static void register(Object object) { 41 | for (final Method method : object.getClass().getDeclaredMethods()) { 42 | if (isMethodBad(method)) { 43 | continue; 44 | } 45 | 46 | register(method, object); 47 | } 48 | } 49 | 50 | /** 51 | * Registers the methods marked with the EventTarget annotation and that require 52 | * the specified Event as the parameter in the class of the given Object. 53 | * 54 | * @param object 55 | * Object that contains the Method you want to register. 56 | * @param Parameter 57 | * class for the marked method we are looking for. 58 | */ 59 | public static void register(Object object, Class eventClass) { 60 | for (final Method method : object.getClass().getDeclaredMethods()) { 61 | if (isMethodBad(method, eventClass)) { 62 | continue; 63 | } 64 | 65 | register(method, object); 66 | } 67 | } 68 | 69 | /** 70 | * Unregisters all the methods inside the Object that are marked with the EventTarget annotation. 71 | * 72 | * @param object 73 | * Object of which you want to unregister all Methods. 74 | */ 75 | public static void unregister(Object object) { 76 | for (final List dataList : REGISTRY_MAP.values()) { 77 | for (final MethodData data : dataList) { 78 | if (data.getSource().equals(object)) { 79 | dataList.remove(data); 80 | } 81 | } 82 | } 83 | 84 | cleanMap(true); 85 | } 86 | 87 | /** 88 | * Unregisters all the methods in the given Object that have the specified class as a parameter. 89 | * 90 | * @param object 91 | * Object that implements the Listener interface. 92 | * @param Parameter 93 | * class for the method to remove. 94 | */ 95 | public static void unregister(Object object, Class eventClass) { 96 | if (REGISTRY_MAP.containsKey(eventClass)) { 97 | for (final MethodData data : REGISTRY_MAP.get(eventClass)) { 98 | if (data.getSource().equals(object)) { 99 | REGISTRY_MAP.get(eventClass).remove(data); 100 | } 101 | } 102 | 103 | cleanMap(true); 104 | } 105 | } 106 | 107 | /** 108 | * Registers a new MethodData to the HashMap. 109 | * If the HashMap already contains the key of the Method's first argument it will add 110 | * a new MethodData to key's matching list and sorts it based on Priority. @see com.darkmagician6.eventapi.types.Priority 111 | * Otherwise it will put a new entry in the HashMap with a the first argument's class 112 | * and a new CopyOnWriteArrayList containing the new MethodData. 113 | * 114 | * @param method 115 | * Method to register to the HashMap. 116 | * @param object 117 | * Source object of the method. 118 | */ 119 | private static void register(Method method, Object object) { 120 | Class indexClass = (Class) method.getParameterTypes()[0]; 121 | //New MethodData from the Method we are registering. 122 | final MethodData data = new MethodData(object, method, method.getAnnotation(EventTarget.class).value()); 123 | 124 | //Set's the method to accessible so that we can also invoke it if it's protected or private. 125 | if (!data.getTarget().isAccessible()) { 126 | data.getTarget().setAccessible(true); 127 | } 128 | 129 | if (REGISTRY_MAP.containsKey(indexClass)) { 130 | if (!REGISTRY_MAP.get(indexClass).contains(data)) { 131 | REGISTRY_MAP.get(indexClass).add(data); 132 | sortListValue(indexClass); 133 | } 134 | } else { 135 | REGISTRY_MAP.put(indexClass, new CopyOnWriteArrayList() { 136 | //Eclipse was bitching about a serialVersionUID. 137 | private static final long serialVersionUID = 666L; { 138 | add(data); 139 | } 140 | }); 141 | } 142 | } 143 | 144 | /** 145 | * Removes an entry based on the key value in the map. 146 | * 147 | * @param indexClass 148 | * They index key in the map of which the entry should be removed. 149 | */ 150 | public static void removeEntry(Class indexClass) { 151 | Iterator, List>> mapIterator = REGISTRY_MAP.entrySet().iterator(); 152 | 153 | while (mapIterator.hasNext()) { 154 | if (mapIterator.next().getKey().equals(indexClass)) { 155 | mapIterator.remove(); 156 | break; 157 | } 158 | } 159 | } 160 | 161 | /** 162 | * Cleans up the map entries. 163 | * Uses an iterator to make sure that the entry is completely removed. 164 | * 165 | * @param onlyEmptyEntries 166 | * If true only remove the entries with an empty list, otherwise remove all the entries. 167 | */ 168 | public static void cleanMap(boolean onlyEmptyEntries) { 169 | Iterator, List>> mapIterator = REGISTRY_MAP.entrySet().iterator(); 170 | 171 | while (mapIterator.hasNext()) { 172 | if (!onlyEmptyEntries || mapIterator.next().getValue().isEmpty()) { 173 | mapIterator.remove(); 174 | } 175 | } 176 | } 177 | 178 | /** 179 | * Sorts the List that matches the corresponding Event class based on priority value. 180 | * 181 | * @param indexClass 182 | * The Event class index in the HashMap of the List to sort. 183 | */ 184 | private static void sortListValue(Class indexClass) { 185 | List sortedList = new CopyOnWriteArrayList(); 186 | 187 | for (final byte priority : Priority.VALUE_ARRAY) { 188 | for (final MethodData data : REGISTRY_MAP.get(indexClass)) { 189 | if (data.getPriority() == priority) { 190 | sortedList.add(data); 191 | } 192 | } 193 | } 194 | 195 | //Overwriting the existing entry. 196 | REGISTRY_MAP.put(indexClass, sortedList); 197 | } 198 | 199 | /** 200 | * Checks if the method does not meet the requirements to be used to receive event calls from the Dispatcher. 201 | * Performed checks: Checks if the parameter length is not 1 and if the EventTarget annotation is not present. 202 | * 203 | * @param method 204 | * Method to check. 205 | * 206 | * @return True if the method should not be used for receiving event calls from the Dispatcher. 207 | * 208 | * @see com.darkmagician6.eventapi.EventTarget 209 | */ 210 | private static boolean isMethodBad(Method method) { 211 | return method.getParameterTypes().length != 1 || !method.isAnnotationPresent(EventTarget.class); 212 | } 213 | 214 | /** 215 | * Checks if the method does not meet the requirements to be used to receive event calls from the Dispatcher. 216 | * Performed checks: Checks if the parameter class of the method is the same as the event we want to receive. 217 | * 218 | * @param method 219 | * Method to check. 220 | * @param Class 221 | * of the Event we want to find a method for receiving it. 222 | * 223 | * @return True if the method should not be used for receiving event calls from the Dispatcher. 224 | * 225 | * @see com.darkmagician6.eventapi.EventTarget 226 | */ 227 | private static boolean isMethodBad(Method method, Class eventClass) { 228 | return isMethodBad(method) || !method.getParameterTypes()[0].equals(eventClass); 229 | } 230 | 231 | /** 232 | * Call's an event and invokes the right methods that are listening to the event call. 233 | * First get's the matching list from the registry map based on the class of the event. 234 | * Then it checks if the list is not null. After that it will check if the event is an instance of 235 | * EventStoppable and if so it will add an extra check when looping trough the data. 236 | * If the Event was an instance of EventStoppable it will check every loop if the EventStoppable is stopped, and if 237 | * it is it will break the loop, thus stopping the call. 238 | * For every MethodData in the list it will invoke the Data's method with the Event as the argument. 239 | * After that is all done it will return the Event. 240 | * 241 | * @param event 242 | * Event to dispatch. 243 | * 244 | * @return Event in the state after dispatching it. 245 | */ 246 | public static final Event call(final Event event) { 247 | List dataList = REGISTRY_MAP.get(event.getClass()); 248 | 249 | if (dataList != null) { 250 | if (event instanceof EventStoppable) { 251 | EventStoppable stoppable = (EventStoppable) event; 252 | 253 | for (final MethodData data : dataList) { 254 | invoke(data, event); 255 | 256 | if (stoppable.isStopped()) { 257 | break; 258 | } 259 | } 260 | } else { 261 | for (final MethodData data : dataList) { 262 | invoke(data, event); 263 | } 264 | } 265 | } 266 | 267 | return event; 268 | } 269 | 270 | /** 271 | * Invokes a MethodData when an Event call is made. 272 | * 273 | * @param data 274 | * The data of which the targeted Method should be invoked. 275 | * @param argument 276 | * The called Event which should be used as an argument for the targeted Method. 277 | * 278 | * TODO: Error messages. 279 | */ 280 | private static void invoke(MethodData data, Event argument) { 281 | try { 282 | data.getTarget().invoke(data.getSource(), argument); 283 | } catch (IllegalAccessException e) { 284 | } catch (IllegalArgumentException e) { 285 | } catch (InvocationTargetException e) { 286 | } 287 | } 288 | 289 | /** 290 | * 291 | * @author DarkMagician6 292 | * @since January 2, 2014 293 | */ 294 | private static final class MethodData { 295 | 296 | private final Object source; 297 | 298 | private final Method target; 299 | 300 | private final byte priority; 301 | 302 | /** 303 | * Sets the values of the data. 304 | * 305 | * @param source 306 | * The source Object of the data. Used by the VM to 307 | * determine to which object it should send the call to. 308 | * @param target 309 | * The targeted Method to which the Event should be send to. 310 | * @param priority 311 | * The priority of this Method. Used by the registry to sort 312 | * the data on. 313 | */ 314 | public MethodData(Object source, Method target, byte priority) { 315 | this.source = source; 316 | this.target = target; 317 | this.priority = priority; 318 | } 319 | 320 | /** 321 | * Gets the source Object of the data. 322 | * 323 | * @return Source Object of the targeted Method. 324 | */ 325 | public Object getSource() { 326 | return source; 327 | } 328 | 329 | /** 330 | * Gets the targeted Method. 331 | * 332 | * @return The Method that is listening to certain Event calls. 333 | */ 334 | public Method getTarget() { 335 | return target; 336 | } 337 | 338 | /** 339 | * Gets the priority value of the targeted Method. 340 | * 341 | * @return The priority value of the targeted Method. 342 | */ 343 | public byte getPriority() { 344 | return priority; 345 | } 346 | 347 | } 348 | 349 | public static Map, List> getRegistryMap() { 350 | return REGISTRY_MAP; 351 | } 352 | } 353 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/EventTarget.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi; 2 | 3 | import com.darkmagician6.eventapi.types.Priority; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * Marks a method so that the EventManager knows that it should be registered. 9 | * The priority of the method is also set with this. 10 | * 11 | * @author DarkMagician6 12 | * @see com.darkmagician6.eventapi.types.Priority 13 | * @since July 30, 2013 14 | */ 15 | @Documented 16 | @Target(ElementType.METHOD) 17 | @Retention(RetentionPolicy.RUNTIME) 18 | public @interface EventTarget { 19 | 20 | byte value() default Priority.MEDIUM; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/events/Cancellable.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi.events; 2 | 3 | /** 4 | * Simple interface which should be implemented in events that can be cancelled. 5 | * 6 | * @author DarkMagician6 7 | * @since August 27, 2013 8 | */ 9 | public interface Cancellable { 10 | 11 | /** 12 | * Gets the current cancelled state of the event. 13 | * 14 | * @return True if the event is cancelled. 15 | */ 16 | boolean isCancelled(); 17 | 18 | /** 19 | * Sets the cancelled state of the event. 20 | * 21 | * @param state 22 | * Whether the event should be cancelled or not. 23 | */ 24 | void setCancelled(boolean state); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/events/Event.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi.events; 2 | 3 | /** 4 | * The most basic form of an event. 5 | * You have to implement this interface in order for the EventAPI to recognize the event. 6 | * 7 | * @author DarkMagician6 8 | * @since July 30, 2013 9 | */ 10 | public interface Event { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/events/EventStoppable.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi.events; 2 | 3 | /** 4 | * The most basic form of an stoppable Event. 5 | * Stoppable events are called seperate from other events and the calling of methods is stopped 6 | * as soon as the EventStoppable is stopped. 7 | * 8 | * @author DarkMagician6 9 | * @since 26-9-13 10 | */ 11 | public abstract class EventStoppable implements Event { 12 | 13 | private boolean stopped; 14 | 15 | /** 16 | * No need for the constructor to be public. 17 | */ 18 | protected EventStoppable() { 19 | } 20 | 21 | /** 22 | * Sets the stopped state to true. 23 | */ 24 | public void stop() { 25 | stopped = true; 26 | } 27 | 28 | /** 29 | * Checks the stopped boolean. 30 | * 31 | * @return 32 | * True if the EventStoppable is stopped. 33 | */ 34 | public boolean isStopped() { 35 | return stopped; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/events/Typed.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi.events; 2 | 3 | 4 | /** 5 | * Simple interface that should be implemented in typed events. 6 | * A typed event is an event that can be called on multiple places 7 | * with the type defining where it was called. 8 | *

9 | * The type should be defined in the constructor when the new instance 10 | * of the event is created. 11 | * 12 | * @author DarkMagician6 13 | * @since August 27, 2013 14 | */ 15 | public interface Typed { 16 | 17 | /** 18 | * Gets the current type of the event. 19 | * 20 | * @return The type ID of the event. 21 | */ 22 | byte getType(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/events/callables/EventCancellable.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi.events.callables; 2 | 3 | import com.darkmagician6.eventapi.events.Cancellable; 4 | import com.darkmagician6.eventapi.events.Event; 5 | 6 | /** 7 | * Abstract example implementation of the Cancellable interface. 8 | * 9 | * @author DarkMagician6 10 | * @since August 27, 2013 11 | */ 12 | public abstract class EventCancellable implements Event, Cancellable { 13 | 14 | private boolean cancelled; 15 | 16 | protected EventCancellable() { 17 | } 18 | 19 | /** 20 | * @see com.darkmagician6.eventapi.events.Cancellable.isCancelled 21 | */ 22 | @Override 23 | public boolean isCancelled() { 24 | return cancelled; 25 | } 26 | 27 | /** 28 | * @see com.darkmagician6.eventapi.events.Cancellable.setCancelled 29 | */ 30 | @Override 31 | public void setCancelled(boolean state) { 32 | cancelled = state; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/events/callables/EventTyped.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi.events.callables; 2 | 3 | import com.darkmagician6.eventapi.events.Event; 4 | import com.darkmagician6.eventapi.events.Typed; 5 | 6 | /** 7 | * Abstract example implementation of the Typed interface. 8 | * 9 | * @author DarkMagician6 10 | * @since August 27, 2013 11 | */ 12 | public abstract class EventTyped implements Event, Typed { 13 | 14 | private final byte type; 15 | 16 | /** 17 | * Sets the type of the event when it's called. 18 | * 19 | * @param eventType 20 | * The type ID of the event. 21 | */ 22 | protected EventTyped(byte eventType) { 23 | type = eventType; 24 | } 25 | 26 | /** 27 | * @see com.darkmagician6.eventapi.events.Typed.getType 28 | */ 29 | @Override 30 | public byte getType() { 31 | return type; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/types/EventType.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi.types; 2 | 3 | /** 4 | * Types that can be used for typed events. 5 | * 6 | * @author DarkMagician6 7 | * @since August 27, 2013 8 | */ 9 | public class EventType { 10 | 11 | /** 12 | * Used to define the type of a typed event. 13 | */ 14 | public static final byte 15 | PRE = 0, 16 | ON = 1, 17 | POST = 2, 18 | SEND = 3, 19 | RECIEVE = 4; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/darkmagician6/eventapi/types/Priority.java: -------------------------------------------------------------------------------- 1 | package com.darkmagician6.eventapi.types; 2 | 3 | /** 4 | * The priority for the dispatcher to determine what method should be invoked first. 5 | * Ram was talking about the memory usage of the way I store the data so I decided 6 | * to just use bytes for the priority because they take up only 8 bits of memory 7 | * per value compared to the 32 bits per value of an enum (Same as an integer). 8 | * 9 | * @author DarkMagician6 10 | * @since August 3, 2013 11 | */ 12 | public final class Priority { 13 | 14 | public static final byte 15 | /** 16 | * Highest priority, called first. 17 | */ 18 | HIGHEST = 0, 19 | /** 20 | * High priority, called after the highest priority. 21 | */ 22 | HIGH = 1, 23 | /** 24 | * Medium priority, called after the high priority. 25 | */ 26 | MEDIUM = 2, 27 | /** 28 | * Low priority, called after the medium priority. 29 | */ 30 | LOW = 3, 31 | /** 32 | * Lowest priority, called after all the other priorities. 33 | */ 34 | LOWEST = 4; 35 | 36 | /** 37 | * Array containing all the prioriy values. 38 | */ 39 | public static final byte[] VALUE_ARRAY; 40 | 41 | /** 42 | * Sets up the VALUE_ARRAY the first time anything in this class is called. 43 | */ 44 | static { 45 | VALUE_ARRAY = new byte[]{ 46 | HIGHEST, 47 | HIGH, 48 | MEDIUM, 49 | LOW, 50 | LOWEST 51 | }; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/agent/ClientAgent.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.agent; 2 | 3 | import me.dickmeister.agent.modules.AgentModule; 4 | import me.dickmeister.agent.modules.impl.MinecraftJarInjectorModule; 5 | import me.dickmeister.agent.modules.impl.MinecraftQueueFinderModule; 6 | import me.dickmeister.agent.modules.impl.VersionFinderModule; 7 | import me.dickmeister.agent.modules.impl.VersionMappingDownloaderModule; 8 | import me.dickmeister.common.util.LogUtil; 9 | 10 | import java.lang.instrument.Instrumentation; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class ClientAgent { 15 | 16 | private static final List moduleList = new ArrayList<>(); 17 | 18 | public static void agentmain(String agentArgs, Instrumentation inst) { 19 | LogUtil.log("Loading modules..."); 20 | moduleList.add(new VersionFinderModule()); 21 | moduleList.add(new VersionMappingDownloaderModule()); 22 | moduleList.add(new MinecraftQueueFinderModule()); 23 | moduleList.add(new MinecraftJarInjectorModule()); 24 | 25 | LogUtil.log("Executing modules..."); 26 | Object returnCache = new Object(); 27 | for(AgentModule m : moduleList) { 28 | try{ 29 | returnCache = m.execute(inst,returnCache); 30 | LogUtil.log("Executed module: " + m.getClass().getName()); 31 | }catch(Exception e){ 32 | e.printStackTrace(); 33 | LogUtil.log("Failed to execute module " + m.getClass().getName()); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/agent/attacher/AgentAttacher.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.agent.attacher; 2 | 3 | import com.sun.tools.attach.VirtualMachine; 4 | 5 | import java.lang.management.ManagementFactory; 6 | 7 | public class AgentAttacher { 8 | 9 | public static void attachDynamic(String jarFilePath, String pid) throws Exception { 10 | VirtualMachine vm = VirtualMachine.attach(pid); 11 | vm.loadAgent(jarFilePath, ""); 12 | vm.detach(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/agent/modules/AgentModule.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.agent.modules; 2 | 3 | import java.lang.instrument.Instrumentation; 4 | 5 | public abstract class AgentModule { 6 | 7 | public abstract Object execute(Instrumentation instrumentation,Object arg) throws Exception; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/agent/modules/impl/MinecraftJarInjectorModule.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.agent.modules.impl; 2 | 3 | import me.dickmeister.agent.ClientAgent; 4 | import me.dickmeister.agent.modules.AgentModule; 5 | import me.dickmeister.common.util.LogUtil; 6 | 7 | import java.io.File; 8 | import java.lang.instrument.Instrumentation; 9 | import java.net.URL; 10 | import java.net.URLClassLoader; 11 | import java.util.Objects; 12 | import java.util.Queue; 13 | 14 | public class MinecraftJarInjectorModule extends AgentModule { 15 | @Override 16 | public Object execute(Instrumentation instrumentation, Object arg) throws Exception { 17 | if(Objects.isNull(arg)) return null; 18 | var queue = (Queue) arg; 19 | var filePath = ClientAgent.class.getProtectionDomain().getCodeSource().getLocation().getPath();; 20 | queue.add(() -> { 21 | try { 22 | var file = new File(filePath); 23 | var classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()}, Thread.currentThread().getContextClassLoader()); 24 | 25 | var clazz = classLoader.loadClass("me.dickmeister.client.ClientMain"); 26 | var instance = clazz.newInstance(); 27 | clazz.getDeclaredMethod("invokeClient",Instrumentation.class).invoke(instance,instrumentation); 28 | 29 | Thread.currentThread().setContextClassLoader(classLoader); 30 | }catch(Exception e){ 31 | e.printStackTrace(); 32 | } 33 | }); 34 | return null; //Last module 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/agent/modules/impl/MinecraftQueueFinderModule.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.agent.modules.impl; 2 | 3 | import me.dickmeister.agent.modules.AgentModule; 4 | 5 | import java.lang.instrument.Instrumentation; 6 | import java.util.Objects; 7 | import java.util.Queue; 8 | import java.util.Scanner; 9 | 10 | public class MinecraftQueueFinderModule extends AgentModule { 11 | 12 | @Override 13 | public Object execute(Instrumentation instrumentation, Object arg) throws Exception { 14 | var mappings = (String) arg; 15 | var mcClass = findMinecraftClass(mappings); 16 | var mcInstance = getMinecraftInstance(mcClass,mappings,instrumentation); 17 | var taskQueue = getMinecraftTaskQueue(mcInstance,mappings); 18 | 19 | if(Objects.isNull(taskQueue)){ 20 | System.out.println("Failed to find task queue"); 21 | return null; 22 | } 23 | return taskQueue; 24 | } 25 | 26 | /** 27 | * Get minecraft task queue 28 | * @param minecraftObject minecraft instance 29 | * @param mappingData mapping data 30 | * @return minecraft task queue 31 | * @throws Exception if failed to get queue 32 | */ 33 | private Queue getMinecraftTaskQueue(Object minecraftObject,String mappingData) throws Exception{ 34 | String fieldName = ""; 35 | var scanner = new Scanner(mappingData); 36 | while(scanner.hasNextLine()){ 37 | var line = scanner.nextLine(); 38 | if(line.contains("progressTasks") && line.contains("java.util.Queue progressTasks")){ 39 | fieldName = line.split(" -> ")[1]; 40 | break; 41 | } 42 | } 43 | 44 | var method = minecraftObject.getClass().getDeclaredField(fieldName); 45 | method.setAccessible(true); 46 | return (Queue) method.get(minecraftObject); 47 | } 48 | 49 | /** 50 | * Get minecraft instance 51 | * @param className minecraft class name 52 | * @param mappingData mapping data 53 | * @return minecraft instance 54 | * @throws Exception 55 | */ 56 | private Object getMinecraftInstance(String className,String mappingData,Instrumentation instrumentation) throws Exception{ 57 | 58 | String methodName = ""; 59 | var scanner = new Scanner(mappingData); 60 | while(scanner.hasNextLine()){ 61 | var line = scanner.nextLine(); 62 | if(line.contains("getInstance()")){ 63 | if(line.contains("net.minecraft.client.Minecraft") && line.contains(" -> ")){ 64 | methodName = line.split(" -> ")[1]; 65 | break; 66 | } 67 | } 68 | } 69 | 70 | if(methodName.isEmpty()){ 71 | System.err.println("[PreHook] Failed to find getInstance() method name!"); 72 | return null; 73 | } 74 | 75 | for(Class clazz : instrumentation.getAllLoadedClasses()){ 76 | if(clazz.getSimpleName().equals(className)){ 77 | var method = clazz.getDeclaredMethod(methodName); 78 | method.setAccessible(true); 79 | return method.invoke(null); 80 | } 81 | } 82 | 83 | return null; 84 | } 85 | 86 | /** 87 | * Get minecraft class name 88 | * @param mappingData mapping data 89 | * @return minecraft class name 90 | */ 91 | private String findMinecraftClass(String mappingData){ 92 | var scanner = new Scanner(mappingData); 93 | while(scanner.hasNextLine()){ 94 | var line = scanner.nextLine(); 95 | if(line.contains("net.minecraft.client.Minecraft")){ 96 | if(line.contains(" -> ") && line.endsWith(":") && !line.contains("$")){ 97 | return line.split(" -> ")[1].split(":")[0]; 98 | } 99 | } 100 | } 101 | return null; 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/agent/modules/impl/VersionFinderModule.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.agent.modules.impl; 2 | 3 | import me.dickmeister.agent.modules.AgentModule; 4 | 5 | import java.lang.instrument.Instrumentation; 6 | 7 | public class VersionFinderModule extends AgentModule { 8 | 9 | @Override 10 | public Object execute(Instrumentation instrumentation,Object arg) throws Exception { 11 | var classes = instrumentation.getAllLoadedClasses(); 12 | for (var clazz : classes) { 13 | if(clazz.getSimpleName().equals("ab")) { //SharedConstants 14 | var versionStringField = clazz.getDeclaredField("d"); //VERSION_STRING 15 | return versionStringField.get(null); 16 | } 17 | } 18 | 19 | return null; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/agent/modules/impl/VersionMappingDownloaderModule.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.agent.modules.impl; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonObject; 7 | import me.dickmeister.agent.modules.AgentModule; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.InputStreamReader; 11 | import java.lang.instrument.Instrumentation; 12 | import java.net.URL; 13 | import java.nio.charset.StandardCharsets; 14 | 15 | public class VersionMappingDownloaderModule extends AgentModule { 16 | 17 | private final String VERSION_MANIFEST = "https://launchermeta.mojang.com/mc/game/version_manifest.json"; 18 | 19 | @Override 20 | public Object execute(Instrumentation instrumentation, Object arg) throws Exception { 21 | var gson = new GsonBuilder().create(); 22 | 23 | var versionString = (String) arg; 24 | var manifestData = this.readAllFromURL(VERSION_MANIFEST); 25 | var versionManifestUrl = this.readVersionLists(versionString, gson.fromJson(manifestData, JsonObject.class)); 26 | var mappingsUrl = this.readVersionManifest(gson,versionManifestUrl); 27 | return readAllFromURL(mappingsUrl); 28 | } 29 | 30 | /** 31 | * Get mappings from the client manifest 32 | * @param gson Gson instance 33 | * @param url URL to the client manifest 34 | * @return Mappings url 35 | * @throws Exception If the url is not found 36 | */ 37 | private String readVersionManifest(Gson gson, String url) throws Exception{ 38 | var data = this.readAllFromURL(url); 39 | var object = gson.fromJson(data, JsonObject.class); 40 | var downloads = object.get("downloads").getAsJsonObject(); 41 | var clientMappings = downloads.get("client_mappings").getAsJsonObject(); 42 | return clientMappings.get("url").getAsString(); 43 | } 44 | 45 | /** 46 | * Get version manifest from version lists 47 | * @param versionName The version name to get the manifest for 48 | * @param object The version list object 49 | * @return The manifest url 50 | */ 51 | private String readVersionLists(String versionName, JsonObject object){ 52 | var versions = object.getAsJsonArray("versions"); 53 | for(JsonElement element : versions){ 54 | var version = element.getAsJsonObject(); 55 | if(version.get("id").getAsString().equals(versionName)) return version.get("url").getAsString(); 56 | } 57 | 58 | return null; 59 | } 60 | 61 | /** 62 | * Read all data as string from URL 63 | */ 64 | private String readAllFromURL(String url) throws Exception{ 65 | try (var is = new URL(url).openStream()) { 66 | var reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); 67 | var sb = new StringBuilder(); 68 | int cp; 69 | while ((cp = reader.read()) != -1) { 70 | sb.append((char) cp); 71 | } 72 | return sb.toString(); 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/ClientMain.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client; 2 | 3 | import com.darkmagician6.eventapi.EventManager; 4 | import com.darkmagician6.eventapi.EventTarget; 5 | import me.dickmeister.client.core.command.CommandManager; 6 | import me.dickmeister.client.core.event.EventDistributor; 7 | import me.dickmeister.client.core.event.EventInjector; 8 | import me.dickmeister.client.core.event.impl.ClientInternalTickEvent; 9 | import me.dickmeister.client.core.event.impl.Render2DEvent; 10 | import me.dickmeister.client.core.gui.GuiIngameRenderer; 11 | import me.dickmeister.client.core.module.ModuleManager; 12 | import me.dickmeister.client.core.utils.minecraft.MinecraftUtil; 13 | import me.dickmeister.client.mappings.MappingManager; 14 | import me.dickmeister.client.mappings.VersionMappingsLoader; 15 | import me.dickmeister.client.mappings.loader.MappingsLoader; 16 | import me.dickmeister.client.tasks.TickingTask; 17 | import me.dickmeister.client.transformers.TestTransformer; 18 | import me.dickmeister.client.version.VersionFinder; 19 | import me.dickmeister.common.util.LogUtil; 20 | import org.reflections.Reflections; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import java.lang.instrument.ClassDefinition; 24 | import java.lang.instrument.Instrumentation; 25 | import java.util.concurrent.Executors; 26 | import java.util.concurrent.ScheduledExecutorService; 27 | import java.util.concurrent.TimeUnit; 28 | import java.util.logging.Level; 29 | import java.util.logging.Logger; 30 | 31 | public class ClientMain { 32 | public static final boolean DEBUG = true; 33 | 34 | public static Instrumentation instrumentation; 35 | private boolean initialized = false; 36 | private final ScheduledExecutorService tickingService; 37 | private static ClientMain instance; 38 | 39 | private final MappingManager mappingManager = new MappingManager(); 40 | private final EventDistributor eventDistributor = new EventDistributor(); 41 | private final CommandManager commandManager = new CommandManager(); 42 | private final ModuleManager moduleManager = new ModuleManager(); 43 | 44 | private MinecraftUtil minecraftUtil; 45 | 46 | public ClientMain(){ 47 | tickingService = Executors.newSingleThreadScheduledExecutor(); 48 | instance = this; 49 | } 50 | 51 | public void initialize() throws Exception { 52 | 53 | 54 | Logger.getLogger("org.reflections").setLevel(Level.OFF); 55 | 56 | LogUtil.log("Initializing client..."); 57 | tickingService.scheduleAtFixedRate(new TickingTask(), 0, 50, TimeUnit.MILLISECONDS); 58 | 59 | LogUtil.log("Checking client version..."); 60 | var version = new VersionFinder().findVersion(); 61 | if(version == null) { 62 | LogUtil.log("Failed to find client version!"); 63 | return; 64 | } 65 | 66 | LogUtil.log("Client version: %s", version.getVersion()); 67 | LogUtil.log("Client protocol: %s", version.getProtocol()); 68 | 69 | LogUtil.log("Downloading mappings..."); 70 | var mappingsLoader = new MappingsLoader(mappingManager); 71 | var mappingsUrl = new VersionMappingsLoader().loadFromVersion(version); 72 | mappingsLoader.loadFromUrl(mappingsUrl); 73 | 74 | if(mappingManager.getMappedClasses().isEmpty()){ 75 | LogUtil.err("Failed to load mappings data!"); 76 | return; 77 | } 78 | 79 | LogUtil.log("Loaded %s mapped classes!", mappingManager.getMappedClasses().size()); 80 | 81 | LogUtil.log("Injecting events..."); 82 | var eventInjector = new EventInjector(); 83 | eventInjector.initialize(); 84 | 85 | commandManager.initialize(); 86 | moduleManager.initialize(); 87 | 88 | minecraftUtil = MinecraftUtil.getFromVersion(version.getVersion()); 89 | if(minecraftUtil == null){ 90 | LogUtil.err("Unsupported version: %s", version.getVersion()); 91 | return; 92 | } 93 | 94 | LogUtil.log("Client initialized!"); 95 | 96 | instrumentation.addTransformer(new TestTransformer()); 97 | var clazz = ClientMain.getMappingManager().translateClassName("net.minecraft.world.entity.player.Player"); 98 | instrumentation.retransformClasses(Class.forName(clazz)); 99 | 100 | this.initialized = true; 101 | } 102 | 103 | public void start(){ 104 | if(!initialized){ 105 | LogUtil.err("Failed to start: client is not initialized!"); 106 | return; 107 | } 108 | 109 | EventManager.register(new GuiIngameRenderer()); 110 | LogUtil.log("Starting client..."); 111 | } 112 | 113 | public static void invokeClient(Instrumentation inst){ 114 | try { 115 | instrumentation = inst; 116 | instance.initialize(); 117 | instance.start(); 118 | }catch(Exception e){ 119 | LogUtil.err("Failed to start client!"); 120 | e.printStackTrace(); 121 | } 122 | } 123 | 124 | public static ClientMain getInstance() { 125 | return instance; 126 | } 127 | 128 | public EventDistributor getEventDistributor() { 129 | return eventDistributor; 130 | } 131 | 132 | public ModuleManager getModuleManager() { 133 | return moduleManager; 134 | } 135 | 136 | public CommandManager getCommandManager() { 137 | return commandManager; 138 | } 139 | public static MinecraftUtil getMinecraftUtil() { 140 | return getInstance().minecraftUtil; 141 | } 142 | 143 | public static MappingManager getMappingManager() { 144 | return instance.mappingManager; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/command/Command.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.command; 2 | 3 | public abstract class Command { 4 | 5 | private final String prefix; 6 | private final String usage; 7 | private final String description; 8 | 9 | public Command(String prefix, String usage, String description) { 10 | this.prefix = prefix; 11 | this.usage = usage; 12 | this.description = description; 13 | } 14 | 15 | public abstract void execute(String[] args) throws Exception; 16 | 17 | public String getDescription() { 18 | return description; 19 | } 20 | 21 | public String getPrefix() { 22 | return prefix; 23 | } 24 | 25 | public String getUsage() { 26 | return usage; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/command/CommandManager.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.command; 2 | 3 | import com.darkmagician6.eventapi.EventManager; 4 | import com.darkmagician6.eventapi.EventTarget; 5 | import me.dickmeister.client.ClientMain; 6 | import me.dickmeister.client.core.command.impl.HelpCommand; 7 | import me.dickmeister.client.core.command.impl.HitboxCommand; 8 | import me.dickmeister.client.core.command.impl.PanicCommand; 9 | import me.dickmeister.client.core.command.impl.ToggleCommand; 10 | import me.dickmeister.client.core.event.impl.PlayerChatEvent; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class CommandManager { 16 | 17 | private final List commandList = new ArrayList<>(); 18 | 19 | public void initialize(){ 20 | commandList.add(new HelpCommand()); 21 | commandList.add(new PanicCommand()); 22 | commandList.add(new ToggleCommand()); 23 | commandList.add(new HitboxCommand()); 24 | EventManager.register(this); 25 | } 26 | 27 | @EventTarget 28 | public void onChat(PlayerChatEvent event){ 29 | var message = event.getMessage(); 30 | if(message.startsWith(",")){ 31 | 32 | var args = message.split(" "); 33 | var command = args[0].substring(1); 34 | 35 | var commandObject = commandList.stream().filter(cmd -> cmd.getPrefix().equalsIgnoreCase(command)).findFirst(); 36 | commandObject.ifPresentOrElse(cmd -> { 37 | try { 38 | cmd.execute(args); 39 | } catch (Exception e) { 40 | try { 41 | ClientMain.getMinecraftUtil().sendSystemMessage("&cFailed to execute command!"); 42 | e.printStackTrace(); 43 | }catch(Exception e1){ 44 | e1.printStackTrace(); 45 | } 46 | } 47 | }, () -> { 48 | try { 49 | ClientMain.getMinecraftUtil().sendSystemMessage("&cCommand not found!"); 50 | }catch(Exception e){ 51 | e.printStackTrace(); 52 | } 53 | }); 54 | 55 | 56 | event.setCancelled(true); 57 | } 58 | } 59 | 60 | public List getCommandList() { 61 | return commandList; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/command/impl/HelpCommand.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.command.impl; 2 | 3 | import me.dickmeister.client.ClientMain; 4 | import me.dickmeister.client.core.command.Command; 5 | 6 | public class HelpCommand extends Command { 7 | 8 | public HelpCommand() { 9 | super("help","","Shows list of commands and their usage"); 10 | } 11 | 12 | @Override 13 | public void execute(String[] args) throws Exception { 14 | var cmdManager = ClientMain.getInstance().getCommandManager(); 15 | var spacing = " ".repeat(4); 16 | ClientMain.getMinecraftUtil().sendSystemMessage("&aAvailable commands&7:"); 17 | cmdManager.getCommandList().forEach(cmd -> { 18 | try { 19 | ClientMain.getMinecraftUtil().sendSystemMessage(spacing + "&a," + cmd.getPrefix() + " &7" + cmd.getUsage() + " &8- &7" + cmd.getDescription()); 20 | }catch(Exception e){} 21 | }); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/command/impl/HitboxCommand.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.command.impl; 2 | 3 | import me.dickmeister.client.core.command.Command; 4 | import me.dickmeister.client.core.module.impl.combat.HitboxModule; 5 | 6 | public class HitboxCommand extends Command { 7 | 8 | public HitboxCommand() { 9 | super("hitbox", "[width] [height]", "Expands player hitboxes"); 10 | } 11 | 12 | @Override 13 | public void execute(String[] args) throws Exception { 14 | var width = Double.parseDouble(args[1]); 15 | var height = Double.parseDouble(args[2]); 16 | 17 | HitboxModule.hitboxWidth = (float) width; 18 | HitboxModule.hitboxHeight = (float) height; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/command/impl/PanicCommand.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.command.impl; 2 | 3 | import com.darkmagician6.eventapi.EventManager; 4 | import me.dickmeister.client.ClientMain; 5 | import me.dickmeister.client.core.command.Command; 6 | 7 | public class PanicCommand extends Command { 8 | 9 | public PanicCommand() { 10 | super("panic", "","Panic command"); 11 | } 12 | 13 | @Override 14 | public void execute(String[] args) throws Exception { 15 | EventManager.getRegistryMap().clear(); 16 | ClientMain.getInstance().getModuleManager().getModuleList().forEach(m -> { 17 | if(m.isEnabled()) m.toggle(); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/command/impl/ToggleCommand.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.command.impl; 2 | 3 | import me.dickmeister.client.ClientMain; 4 | import me.dickmeister.client.core.command.Command; 5 | 6 | import java.util.Objects; 7 | 8 | public class ToggleCommand extends Command { 9 | 10 | public ToggleCommand() { 11 | super("toggle", "[modulename]","Toggle cheat module"); 12 | } 13 | 14 | @Override 15 | public void execute(String[] args) throws Exception { 16 | var name = args[1]; 17 | var module = ClientMain.getInstance().getModuleManager().getModuleList().stream().filter(m -> m.getName().equalsIgnoreCase(name)).findFirst().orElse(null); 18 | if(Objects.nonNull(module)){ 19 | module.toggle(); 20 | ClientMain.getMinecraftUtil().sendSystemMessage("&aModule " + module.getName() + " is now " + (module.isEnabled() ? "&aenabled" : "&cdisabled")); 21 | return; 22 | } 23 | 24 | ClientMain.getMinecraftUtil().sendSystemMessage("&cModule not found"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/event/EventDistributor.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.event; 2 | 3 | import com.darkmagician6.eventapi.EventManager; 4 | import me.dickmeister.client.core.event.impl.KeyPressEvent; 5 | import me.dickmeister.client.core.event.impl.PlayerChatEvent; 6 | import me.dickmeister.client.core.event.impl.Render2DEvent; 7 | 8 | public class EventDistributor { 9 | 10 | public boolean onChat(String message){ 11 | var event = new PlayerChatEvent(message); 12 | EventManager.call(event); 13 | return event.isCancelled(); 14 | } 15 | 16 | public boolean onRender(Object poseStack,Float partialTicks){ 17 | var event = new Render2DEvent(poseStack,partialTicks); 18 | EventManager.call(event); 19 | return false; 20 | } 21 | 22 | public boolean onKeyPress(long pressTime, int keyCode, int keyCode1, int pressType, int idkwhatthisis){ 23 | var event = new KeyPressEvent(keyCode,pressType); 24 | EventManager.call(event); 25 | return false; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/event/EventInjector.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.event; 2 | 3 | import javassist.ClassPool; 4 | import javassist.CtClass; 5 | import javassist.CtMethod; 6 | import javassist.LoaderClassPath; 7 | import me.dickmeister.client.ClientMain; 8 | import me.dickmeister.client.core.event.util.EventInitializer; 9 | import me.dickmeister.client.mappings.MappingManager; 10 | import me.dickmeister.common.util.LogUtil; 11 | import net.bytebuddy.ByteBuddy; 12 | import net.bytebuddy.agent.ByteBuddyAgent; 13 | import net.bytebuddy.asm.Advice; 14 | import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; 15 | import net.bytebuddy.dynamic.scaffold.TypeValidation; 16 | import org.reflections.Reflections; 17 | import org.reflections.scanners.SubTypesScanner; 18 | 19 | import java.io.BufferedReader; 20 | import java.io.InputStream; 21 | import java.io.InputStreamReader; 22 | import java.util.HashSet; 23 | import java.util.Set; 24 | import java.util.stream.Collectors; 25 | 26 | import static net.bytebuddy.matcher.ElementMatchers.named; 27 | 28 | public class EventInjector { 29 | 30 | public void initialize(){ 31 | 32 | var loader = Thread.currentThread().getContextClassLoader(); 33 | var mappingManager = ClientMain.getMappingManager(); 34 | 35 | try { 36 | ByteBuddyAgent.install(); 37 | var classes = findAllClassesUsingReflectionsLibrary("me.dickmeister.client.core.event.impl"); 38 | for(var clazz : classes){ 39 | var instance = clazz.newInstance(); 40 | if(instance instanceof EventInitializer){ 41 | ((EventInitializer) instance).initialize(new ByteBuddy(), loader, mappingManager); 42 | LogUtil.log("Injected event: " + clazz.getName()); 43 | } 44 | } 45 | }catch(Exception e){ 46 | e.printStackTrace(); 47 | } 48 | 49 | } 50 | 51 | public Set findAllClassesUsingReflectionsLibrary(String packageName) { 52 | Reflections reflections = new Reflections(packageName, new SubTypesScanner(false)); 53 | return new HashSet<>(reflections.getSubTypesOf(EventInitializer.class)); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/event/impl/ClientInternalTickEvent.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.event.impl; 2 | 3 | import com.darkmagician6.eventapi.events.Event; 4 | import me.dickmeister.client.core.event.util.EventInitializer; 5 | import me.dickmeister.client.mappings.MappingManager; 6 | import net.bytebuddy.ByteBuddy; 7 | 8 | public class ClientInternalTickEvent implements Event, EventInitializer { 9 | @Override 10 | public void initialize(ByteBuddy byteBuddy, ClassLoader loader, MappingManager mappingManager) throws Exception { 11 | //Ignore this, called internally by the client 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/event/impl/KeyPressEvent.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.event.impl; 2 | 3 | import com.darkmagician6.eventapi.events.Event; 4 | import me.dickmeister.client.core.event.util.EventCaller; 5 | import me.dickmeister.client.core.event.util.EventInitializer; 6 | import me.dickmeister.client.mappings.MappingManager; 7 | import net.bytebuddy.ByteBuddy; 8 | import net.bytebuddy.asm.Advice; 9 | import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; 10 | import net.bytebuddy.dynamic.scaffold.TypeValidation; 11 | import net.bytebuddy.implementation.bind.annotation.RuntimeType; 12 | 13 | import static net.bytebuddy.matcher.ElementMatchers.named; 14 | import static net.bytebuddy.matcher.ElementMatchers.takesArgument; 15 | 16 | public class KeyPressEvent implements Event, EventInitializer { 17 | 18 | private int keyCode; 19 | private int pressType; // 1 = pressed, 0 = released, 2 = pressed still 20 | 21 | public KeyPressEvent(int keyCode,int pressType) { 22 | this.keyCode = keyCode; 23 | this.pressType = pressType; 24 | } 25 | 26 | public KeyPressEvent(){} 27 | 28 | public int getKeyCode() { 29 | return keyCode; 30 | } 31 | 32 | public int getPressType() { 33 | return pressType; 34 | } 35 | 36 | @RuntimeType 37 | @Advice.OnMethodEnter(skipOn = Boolean.class) 38 | public static Boolean chat(@RuntimeType long p_90894_, int p_90895_, int p_90896_, int p_90897_, int p_90898_) { 39 | if(EventCaller.callEvent("onKeyPress", p_90894_, p_90895_, p_90896_, p_90897_, p_90898_)) return true; 40 | return null; 41 | } 42 | 43 | @Override 44 | public void initialize(ByteBuddy byteBuddy, ClassLoader loader, MappingManager mappingManager) throws Exception { 45 | // public void keyPress(long p_90894_, int p_90895_, int p_90896_, int p_90897_, int p_90898_) { 46 | 47 | //net.minecraft.client.KeyboardHandler 48 | var className = mappingManager.translateClassName("net.minecraft.client.KeyboardHandler"); 49 | var methodName = mappingManager.translateMethodName("net.minecraft.client.KeyboardHandler","keyPress(JIIII)V"); 50 | 51 | var clazz = loader.loadClass(className); 52 | 53 | byteBuddy.with(TypeValidation.DISABLED) 54 | .redefine(clazz) 55 | .visit(Advice.to(Class.forName("me.dickmeister.client.core.event.impl.KeyPressEvent")).withExceptionPrinting() 56 | .on(named(methodName).and(takesArgument(0, long.class).and(takesArgument(1, int.class).and(takesArgument(2, int.class).and(takesArgument(3, int.class).and(takesArgument(4, int.class)))))))) 57 | .make().load(loader, ClassReloadingStrategy.fromInstalledAgent()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/event/impl/PlayerChatEvent.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.event.impl; 2 | 3 | import com.darkmagician6.eventapi.events.callables.EventCancellable; 4 | import me.dickmeister.client.core.event.util.EventCaller; 5 | import me.dickmeister.client.core.event.util.EventInitializer; 6 | import me.dickmeister.client.mappings.MappingManager; 7 | import net.bytebuddy.ByteBuddy; 8 | import net.bytebuddy.asm.Advice; 9 | import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; 10 | import net.bytebuddy.dynamic.scaffold.TypeValidation; 11 | import net.bytebuddy.implementation.bind.annotation.RuntimeType; 12 | 13 | import static net.bytebuddy.matcher.ElementMatchers.named; 14 | 15 | public class PlayerChatEvent extends EventCancellable implements EventInitializer { 16 | 17 | private String message; 18 | 19 | public PlayerChatEvent(){} 20 | 21 | public PlayerChatEvent(String message) { 22 | this.message = message; 23 | } 24 | 25 | public String getMessage() { 26 | return message; 27 | } 28 | 29 | @RuntimeType 30 | @Advice.OnMethodEnter(skipOn = Boolean.class) 31 | public static Boolean chat(@RuntimeType String p_108740_) { 32 | if(EventCaller.callEvent("onChat", p_108740_)) return true; 33 | return null; 34 | } 35 | 36 | @Override 37 | public void initialize(ByteBuddy byteBuddy, ClassLoader loader, MappingManager mappingManager) throws Exception{ 38 | var clazz = loader.loadClass(mappingManager.translateClassName("net.minecraft.client.player.LocalPlayer")); 39 | var method = mappingManager.translateMethodName("net.minecraft.client.player.LocalPlayer", "chat(Ljava/lang/String;)V"); 40 | byteBuddy.with(TypeValidation.DISABLED) 41 | .redefine(clazz) 42 | .visit(Advice.to(Class.forName("me.dickmeister.client.core.event.impl.PlayerChatEvent")).withExceptionPrinting().on(named(method))) 43 | .make().load(loader, ClassReloadingStrategy.fromInstalledAgent()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/event/impl/Render2DEvent.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.event.impl; 2 | 3 | import com.darkmagician6.eventapi.events.Event; 4 | import me.dickmeister.client.core.event.util.EventCaller; 5 | import me.dickmeister.client.core.event.util.EventInitializer; 6 | import me.dickmeister.client.mappings.MappingManager; 7 | import net.bytebuddy.ByteBuddy; 8 | import net.bytebuddy.asm.Advice; 9 | import net.bytebuddy.dynamic.loading.ClassReloadingStrategy; 10 | import net.bytebuddy.dynamic.scaffold.TypeValidation; 11 | import net.bytebuddy.implementation.bind.annotation.RuntimeType; 12 | 13 | import static net.bytebuddy.matcher.ElementMatchers.*; 14 | 15 | public class Render2DEvent implements Event, EventInitializer { 16 | 17 | private Object poseStack; 18 | private float partialTicks; 19 | 20 | public Render2DEvent(){} 21 | 22 | public Render2DEvent(Object poseStack,float partialTicks) { 23 | this.poseStack = poseStack; 24 | this.partialTicks = partialTicks; 25 | } 26 | 27 | public float getPartialTicks() { 28 | return partialTicks; 29 | } 30 | 31 | public Object getPoseStack() { 32 | return poseStack; 33 | } 34 | 35 | @RuntimeType 36 | @Advice.OnMethodEnter(skipOn = Boolean.class) 37 | public static Boolean onRender(@RuntimeType Object obj, float partialTicks) { 38 | if(EventCaller.callEvent("onRender", obj,partialTicks)) return true; 39 | return null; 40 | } 41 | 42 | @Override 43 | public void initialize(ByteBuddy byteBuddy, ClassLoader loader, MappingManager mappingManager) throws Exception { 44 | var clazz = loader.loadClass(mappingManager.translateClassName("net.minecraft.client.gui.Gui")); 45 | var method = mappingManager.translateMethodName("net.minecraft.client.gui.Gui", "render(Lcom/mojang/blaze3d/vertex/PoseStack;F)V"); 46 | byteBuddy.with(TypeValidation.DISABLED) 47 | .redefine(clazz) 48 | .visit(Advice.to(Class.forName(this.getClass().getName())).withExceptionPrinting().on(named(method).and(takesArgument(1, float.class)))) 49 | .make().load(loader, ClassReloadingStrategy.fromInstalledAgent()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/event/util/EventCaller.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.event.util; 2 | 3 | import me.dickmeister.common.util.LogUtil; 4 | 5 | import java.util.Arrays; 6 | import java.util.Objects; 7 | import java.util.concurrent.atomic.AtomicBoolean; 8 | 9 | public class EventCaller { 10 | 11 | public static boolean callEvent(String methodName,Object... args){ 12 | var classLoader = Thread.currentThread().getContextClassLoader(); 13 | 14 | try { 15 | var clazz = classLoader.loadClass("me.dickmeister.client.ClientMain"); 16 | var instance = clazz.getDeclaredMethod("getInstance").invoke(null); 17 | 18 | var eventDistributor = clazz.getDeclaredMethod("getEventDistributor").invoke(instance); 19 | 20 | var result = new AtomicBoolean(false); 21 | var methods = eventDistributor.getClass().getMethods(); 22 | Arrays.stream(methods).forEach(m -> { 23 | if(m.getName().equals(methodName)){ 24 | try { 25 | result.set((Boolean) m.invoke(eventDistributor, args)); 26 | }catch(Exception e){ 27 | e.printStackTrace(); 28 | } 29 | } 30 | }); 31 | 32 | 33 | return result.get(); 34 | 35 | }catch(Exception e){ 36 | LogUtil.err("Failed to invoke event " + methodName); 37 | e.printStackTrace(); 38 | } 39 | 40 | return false; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/event/util/EventInitializer.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.event.util; 2 | 3 | import me.dickmeister.client.mappings.MappingManager; 4 | import net.bytebuddy.ByteBuddy; 5 | 6 | public interface EventInitializer { 7 | 8 | void initialize(ByteBuddy byteBuddy, ClassLoader loader, MappingManager mappingManager) throws Exception; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/gui/GuiIngameRenderer.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.gui; 2 | 3 | import com.darkmagician6.eventapi.EventTarget; 4 | import me.dickmeister.client.ClientMain; 5 | import me.dickmeister.client.core.event.impl.Render2DEvent; 6 | 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | 9 | public class GuiIngameRenderer { 10 | 11 | @EventTarget 12 | public void onRender2D(Render2DEvent event) { 13 | try { 14 | ClientMain.getMinecraftUtil().drawFontString(event.getPoseStack(), "InjectClient v0", 5, 5, 0xFFFFFF); 15 | 16 | var modules = ClientMain.getInstance().getModuleManager(); 17 | 18 | AtomicInteger yIndex = new AtomicInteger(15); 19 | 20 | modules.getModuleList().forEach(module -> { 21 | if(module.isEnabled()){ 22 | var yPos = yIndex.getAndAdd(10); 23 | try { 24 | ClientMain.getMinecraftUtil().drawFontString(event.getPoseStack(), module.getName(), 5, yPos, 0xFFFFFF); 25 | }catch(Exception e){ 26 | e.printStackTrace(); 27 | } 28 | } 29 | }); 30 | 31 | }catch(Exception e){ 32 | e.printStackTrace(); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/module/Module.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.module; 2 | 3 | import com.darkmagician6.eventapi.EventManager; 4 | 5 | public abstract class Module { 6 | 7 | private final String name; 8 | private final int keybind; 9 | private final String description; 10 | private final ModuleCategory moduleCategory; 11 | 12 | private boolean enabled; 13 | 14 | public Module(String name, int keybind, String description, ModuleCategory moduleCategory) { 15 | this.name = name; 16 | this.keybind = keybind; 17 | this.description = description; 18 | this.moduleCategory = moduleCategory; 19 | } 20 | 21 | public void onEnable(){ 22 | EventManager.register(this); 23 | } 24 | 25 | public void onDisable(){ 26 | EventManager.unregister(this); 27 | } 28 | 29 | public void toggle(){ 30 | this.enabled = !this.enabled; 31 | if(this.enabled){ 32 | onEnable(); 33 | return; 34 | } 35 | 36 | onDisable(); 37 | } 38 | 39 | public String getDescription() { 40 | return description; 41 | } 42 | 43 | public int getKeybind() { 44 | return keybind; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public boolean isEnabled() { 52 | return enabled; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/module/ModuleCategory.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.module; 2 | 3 | public enum ModuleCategory { 4 | 5 | COMBAT, 6 | RENDER, 7 | PLAYER, 8 | OTHER 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/module/ModuleManager.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.module; 2 | 3 | import com.darkmagician6.eventapi.EventManager; 4 | import com.darkmagician6.eventapi.EventTarget; 5 | import me.dickmeister.client.core.event.impl.KeyPressEvent; 6 | import me.dickmeister.client.core.event.util.EventInitializer; 7 | import me.dickmeister.common.util.LogUtil; 8 | import org.reflections.Reflections; 9 | import org.reflections.scanners.SubTypesScanner; 10 | 11 | import java.util.ArrayList; 12 | import java.util.HashSet; 13 | import java.util.List; 14 | 15 | public class ModuleManager { 16 | 17 | private final List moduleList = new ArrayList<>(); 18 | 19 | public void initialize() throws InstantiationException, IllegalAccessException { 20 | Reflections reflections = new Reflections("me.dickmeister.client.core.module.impl", new SubTypesScanner()); 21 | var modules = reflections.getSubTypesOf(Module.class); 22 | 23 | for(var module : modules){ 24 | var instance = module.newInstance(); 25 | LogUtil.log("Loaded module: %s", module.getSimpleName()); 26 | moduleList.add(instance); 27 | } 28 | 29 | EventManager.register(this); 30 | } 31 | 32 | @EventTarget 33 | public void onKeyPress(KeyPressEvent event){ 34 | 35 | if(event.getPressType() == 1){ 36 | getModuleList().forEach(m -> { 37 | var keybind = m.getKeybind(); 38 | 39 | if(keybind != 0 && keybind == event.getKeyCode()) 40 | m.toggle(); 41 | 42 | }); 43 | } 44 | } 45 | 46 | 47 | public void toggleModule(Module module){ 48 | module.toggle(); 49 | } 50 | 51 | public List getModuleList() { 52 | return moduleList; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/module/impl/combat/HitboxModule.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.module.impl.combat; 2 | 3 | import me.dickmeister.client.ClientMain; 4 | import me.dickmeister.client.core.module.Module; 5 | import me.dickmeister.client.core.module.ModuleCategory; 6 | import me.dickmeister.client.core.utils.minecraft.MinecraftUtil; 7 | 8 | import java.awt.event.KeyEvent; 9 | 10 | public class HitboxModule extends Module { 11 | 12 | public HitboxModule() { 13 | super("Hitbox", KeyEvent.VK_K ,"Expands player hitboxes",ModuleCategory.COMBAT); 14 | } 15 | 16 | public static float hitboxWidth = 0.65f; 17 | public static float hitboxHeight = 1.9f; 18 | 19 | //Origin box 0.6F, 1.8F 20 | @Override 21 | public void onEnable() { 22 | super.onEnable(); 23 | 24 | try { 25 | var player = ClientMain.getMinecraftUtil().getLocalPlayer(); 26 | ClientMain.getMinecraftUtil().setPlayerDimensions(player, hitboxWidth, hitboxHeight); 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | } 30 | 31 | } 32 | 33 | @Override 34 | public void onDisable() { 35 | super.onDisable(); 36 | try { 37 | var player = ClientMain.getMinecraftUtil().getLocalPlayer(); 38 | ClientMain.getMinecraftUtil().setPlayerDimensions(player, 0.6F, 1.8F); 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/module/impl/render/ESPModule.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.module.impl.render; 2 | 3 | import com.darkmagician6.eventapi.EventTarget; 4 | import me.dickmeister.client.ClientMain; 5 | import me.dickmeister.client.core.event.impl.ClientInternalTickEvent; 6 | import me.dickmeister.client.core.module.Module; 7 | import me.dickmeister.client.core.module.ModuleCategory; 8 | 9 | import java.awt.event.KeyEvent; 10 | 11 | public class ESPModule extends Module { 12 | public ESPModule() { 13 | super("ESP", KeyEvent.VK_O, "ESP", ModuleCategory.RENDER); 14 | } 15 | 16 | @Override 17 | public void onEnable() { 18 | super.onEnable(); 19 | } 20 | 21 | @Override 22 | public void onDisable() { 23 | super.onDisable(); 24 | 25 | try{ 26 | var players = ClientMain.getMinecraftUtil().getAllPlayers(); 27 | if(players == null){ 28 | return; 29 | } 30 | 31 | for(var obj : players) { 32 | ClientMain.getMinecraftUtil().setSharedFlag(obj, 6, false); 33 | } 34 | }catch(Exception e){ 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | @EventTarget 40 | public void tick(ClientInternalTickEvent event){ 41 | try{ 42 | var players = ClientMain.getMinecraftUtil().getAllPlayers(); 43 | if(players == null){ 44 | return; 45 | } 46 | 47 | for(var obj : players) { 48 | ClientMain.getMinecraftUtil().setSharedFlag(obj, 6, true); 49 | } 50 | }catch(Exception e){ 51 | e.printStackTrace(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/utils/minecraft/MinecraftUtil.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.utils.minecraft; 2 | 3 | import me.dickmeister.client.core.utils.minecraft.impl.MinecraftUtil_118x; 4 | 5 | import java.util.List; 6 | 7 | public abstract class MinecraftUtil { 8 | 9 | public static MinecraftUtil getFromVersion(String versionString){ 10 | if(versionString.startsWith("1.18")){ 11 | return new MinecraftUtil_118x(); 12 | } 13 | 14 | return null; 15 | } 16 | 17 | public abstract void setPlayerDimensions(Object player, float width, float height) throws Exception; 18 | public abstract List getAllPlayers() throws Exception; 19 | public abstract void setSharedFlag(Object entity,int flag, boolean value) throws Exception; 20 | public abstract void drawFontString(Object poseStack,String message,float x,float y,int color) throws Exception; 21 | public abstract Object getFont() throws Exception; 22 | public abstract void sendSystemMessage(String message) throws Exception; 23 | 24 | public abstract Object getLevel() throws Exception; 25 | public abstract Object getLocalPlayer() throws Exception; 26 | public abstract Object getMinecraftInstance() throws Exception; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/core/utils/minecraft/impl/MinecraftUtil_118x.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.core.utils.minecraft.impl; 2 | 3 | import me.dickmeister.client.ClientMain; 4 | import me.dickmeister.client.core.utils.minecraft.MinecraftUtil; 5 | 6 | import java.util.List; 7 | import java.util.UUID; 8 | 9 | public class MinecraftUtil_118x extends MinecraftUtil { 10 | 11 | @Override 12 | public void setPlayerDimensions(Object player, float width, float height) throws Exception{ 13 | var dimensionFieldName = ClientMain.getMappingManager() 14 | .translateFieldName("net.minecraft.world.entity.player.Player","STANDING_DIMENSIONS"); 15 | 16 | var classLoader = Thread.currentThread().getContextClassLoader(); 17 | var className = ClientMain.getMappingManager() 18 | .translateClassName("net.minecraft.world.entity.player.Player"); 19 | 20 | var clazz = classLoader.loadClass(className); 21 | 22 | var dimensionField = clazz.getDeclaredField(dimensionFieldName); 23 | var dimensionObject = dimensionField.get(player); 24 | 25 | var widthFieldName = ClientMain.getMappingManager() 26 | .translateFieldName("net.minecraft.world.entity.EntityDimensions","width"); 27 | var heightFieldName = ClientMain.getMappingManager() 28 | .translateFieldName("net.minecraft.world.entity.EntityDimensions","height"); 29 | 30 | var widthField = dimensionObject.getClass().getDeclaredField(widthFieldName); 31 | var heightField = dimensionObject.getClass().getDeclaredField(heightFieldName); 32 | 33 | widthField.setAccessible(true); 34 | heightField.setAccessible(true); 35 | 36 | widthField.setFloat(dimensionObject, width); 37 | heightField.setFloat(dimensionObject, height); 38 | } 39 | 40 | @Override 41 | public List getAllPlayers() throws Exception { 42 | var level = getLevel(); 43 | //public List players() { 44 | //var players = level.players(); 45 | 46 | var playersMethodName = ClientMain.getMappingManager() 47 | .translateMethodName("net.minecraft.client.multiplayer.ClientLevel","players()Ljava/util/List;"); 48 | var playersMethod = level.getClass().getDeclaredMethod(playersMethodName); 49 | 50 | return (List) playersMethod.invoke(level); 51 | } 52 | 53 | @Override 54 | public void setSharedFlag(Object entity, int flag, boolean value) throws Exception { 55 | //protected void setSharedFlag(int p_20116_, boolean p_20117_) { 56 | var classLoader = Thread.currentThread().getContextClassLoader(); 57 | 58 | var entityClassName = ClientMain.getMappingManager().translateClassName("net.minecraft.world.entity.Entity"); 59 | var entityClass = classLoader.loadClass(entityClassName); 60 | 61 | var setSharedFlagMethodName = ClientMain.getMappingManager() 62 | .translateMethodName("net.minecraft.world.entity.Entity", "setSharedFlag(IZ)V"); 63 | 64 | var method = entityClass.getDeclaredMethod(setSharedFlagMethodName, int.class, boolean.class); 65 | method.setAccessible(true); 66 | method.invoke(entity, flag, value); 67 | } 68 | 69 | @Override 70 | public void drawFontString(Object poseStack, String message, float x, float y, int color) throws Exception { 71 | //public int draw(PoseStack p_92884_, String p_92885_, float p_92886_, float p_92887_, int p_92888_) { 72 | 73 | var methodMapping = ClientMain.getMappingManager().translateMethodName( 74 | "net.minecraft.client.gui.Font","draw(Lcom/mojang/blaze3d/vertex/PoseStack;Ljava/lang/String;FFI)I"); 75 | 76 | var fontInstance = getFont(); 77 | var drawMethod = fontInstance.getClass().getMethod(methodMapping, 78 | poseStack.getClass(), String.class, float.class, float.class, int.class); 79 | 80 | drawMethod.invoke(fontInstance, poseStack, message, x, y, color); 81 | } 82 | 83 | @Override 84 | public Object getFont() throws Exception { 85 | var mcInstance = getMinecraftInstance(); 86 | //public final Font font; 87 | var font = mcInstance.getClass().getDeclaredField( 88 | ClientMain.getMappingManager().translateFieldName("net.minecraft.client.Minecraft", "font")); 89 | 90 | return font.get(mcInstance); 91 | } 92 | 93 | @Override 94 | public void sendSystemMessage(String message) throws Exception { 95 | message = message.replace("&","§"); 96 | 97 | var player = getLocalPlayer(); 98 | var sendSystemMessageMethodName = ClientMain.getMappingManager() 99 | .translateMethodName("net.minecraft.client.player.LocalPlayer", 100 | "sendMessage(Lnet/minecraft/network/chat/Component;Ljava/util/UUID;)V"); 101 | 102 | var componentClass = Class.forName(ClientMain.getMappingManager() 103 | .translateClassName("net.minecraft.network.chat.Component")); 104 | var textComponentClass = Class.forName(ClientMain.getMappingManager() 105 | .translateClassName("net.minecraft.network.chat.TextComponent")); 106 | 107 | var sendMessageMethod = player.getClass().getDeclaredMethod(sendSystemMessageMethodName, componentClass, UUID.class); 108 | 109 | var textComponentInstance = textComponentClass.getConstructor(String.class).newInstance(message); 110 | sendMessageMethod.invoke(player,textComponentInstance,UUID.randomUUID()); 111 | } 112 | 113 | @Override 114 | public Object getLevel() throws Exception { 115 | var mcInstance = getMinecraftInstance(); 116 | 117 | var levelFieldName = ClientMain.getMappingManager().translateFieldName("net.minecraft.client.Minecraft", "level"); 118 | return mcInstance.getClass().getDeclaredField(levelFieldName).get(mcInstance); 119 | } 120 | 121 | @Override 122 | public Object getLocalPlayer() throws Exception { 123 | var instance = getMinecraftInstance(); 124 | var playerFieldName = ClientMain.getMappingManager().translateFieldName("net.minecraft.client.Minecraft", "player"); 125 | var playerField = instance.getClass().getDeclaredField(playerFieldName); 126 | 127 | return playerField.get(instance); 128 | } 129 | 130 | @Override 131 | public Object getMinecraftInstance() throws Exception { 132 | var classLoader = Thread.currentThread().getContextClassLoader(); 133 | var mcClassName = ClientMain.getMappingManager().translateClassName("net.minecraft.client.Minecraft"); 134 | var mcGetInstanceMethodName = ClientMain.getMappingManager() 135 | .translateMethodName("net.minecraft.client.Minecraft", 136 | "getInstance()Lnet/minecraft/client/Minecraft;"); 137 | 138 | var mcClass = classLoader.loadClass(mcClassName); 139 | var mcInstance = mcClass.getMethod(mcGetInstanceMethodName).invoke(null); 140 | 141 | return mcInstance; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/MappingManager.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings; 2 | 3 | import me.dickmeister.client.mappings.proguard.objects.MappedClass; 4 | import me.dickmeister.client.mappings.proguard.objects.MappedField; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class MappingManager { 10 | 11 | private final Map mappedClasses = new HashMap<>(); 12 | 13 | public String translateClassName(String className){ 14 | return mappedClasses.get(className).getNewClassName(); 15 | } 16 | 17 | public String translateMethodName(String className,String methodName){ 18 | return mappedClasses.get(className).getMappedMethodMap().get(methodName).getNewMethodName(); 19 | } 20 | 21 | public String translateFieldName(String className,String fieldName){ 22 | var mappedClass = mappedClasses.get(className); 23 | var field = mappedClass.getMappedFieldMap().get(fieldName); 24 | return field.getNewFieldName(); 25 | } 26 | 27 | public String getFieldName(String className,String fieldName){ 28 | var mappedClass = mappedClasses.get(className); 29 | var field = mappedClass.getMappedFieldMap().values().stream().filter(val -> val.getNewFieldName().equals(fieldName)).findFirst(); 30 | return field.map(MappedField::getFieldName).orElse(null); 31 | } 32 | 33 | public Class getClass(String className) throws ClassNotFoundException{ 34 | return Class.forName(translateClassName(className)); 35 | } 36 | 37 | public Map getMappedClasses() { 38 | return mappedClasses; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/VersionMappingsLoader.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonObject; 7 | import me.dickmeister.client.version.VersionFinder; 8 | import me.dickmeister.common.util.LogUtil; 9 | import me.dickmeister.common.util.URLUtils; 10 | 11 | public class VersionMappingsLoader { 12 | private final Gson gson = new GsonBuilder().create(); 13 | 14 | public String loadFromVersion(VersionFinder.ClientVersion clientVersion){ 15 | LogUtil.log("Loading manifest data for version: %s", clientVersion.getVersion()); 16 | try{ 17 | var data = URLUtils.readAllFromUrl("https://launchermeta.mojang.com/mc/game/version_manifest.json"); 18 | var object = this.gson.fromJson(data, JsonObject.class); 19 | var versionManifestUrl = this.readVersionList(object,clientVersion); 20 | var mappingsUrl = this.readVersionManifest(versionManifestUrl); 21 | 22 | LogUtil.log("Found mappings url: " + mappingsUrl); 23 | return mappingsUrl; 24 | }catch(Exception e){ 25 | LogUtil.err("Failed to read version list from URL!"); 26 | LogUtil.err(e.getClass().getSimpleName() + " " + e.getMessage()); 27 | } 28 | 29 | return null; 30 | } 31 | 32 | private String readVersionManifest(String url){ 33 | try{ 34 | var data = URLUtils.readAllFromUrl(url); 35 | var object = gson.fromJson(data,JsonObject.class); 36 | 37 | var downloads = object.get("downloads").getAsJsonObject(); 38 | var clientMappings = downloads.get("client_mappings").getAsJsonObject(); 39 | return clientMappings.get("url").getAsString(); 40 | }catch(Exception e){ 41 | LogUtil.err("Failed to read version manifest!"); 42 | } 43 | return null; 44 | } 45 | 46 | private String readVersionList(JsonObject object, VersionFinder.ClientVersion clientVersion){ 47 | try{ 48 | LogUtil.log("Reading version list..."); 49 | var versions = object.getAsJsonArray("versions"); 50 | for(JsonElement element : versions){ 51 | var version = element.getAsJsonObject(); 52 | if(version.get("id").getAsString().equals(clientVersion.getVersion())){ 53 | LogUtil.log("Found version manifest for: " + clientVersion.getVersion()); 54 | return version.get("url").getAsString(); 55 | } 56 | } 57 | }catch(Exception e){ 58 | LogUtil.err("Failed to read version manifest!"); 59 | return null; 60 | } 61 | LogUtil.err("No matching version found!"); 62 | return null; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/loader/MappingsLoader.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings.loader; 2 | 3 | import me.dickmeister.client.mappings.MappingManager; 4 | import me.dickmeister.client.mappings.proguard.MappingReader; 5 | import me.dickmeister.client.mappings.proguard.processor.impl.ClientMappingProcessor; 6 | import me.dickmeister.common.util.LogUtil; 7 | import me.dickmeister.common.util.URLUtils; 8 | 9 | public class MappingsLoader { 10 | 11 | private final MappingManager manager; 12 | 13 | public MappingsLoader(MappingManager manager) { 14 | this.manager = manager; 15 | } 16 | 17 | public void loadFromUrl(String url){ 18 | try { 19 | var data = URLUtils.readAllFromUrl(url); 20 | var reader = new MappingReader(data); 21 | 22 | var startTime = System.currentTimeMillis(); 23 | LogUtil.log("Loading mapping data to memory..."); 24 | reader.pump(new ClientMappingProcessor(manager)); 25 | 26 | var endTime = System.currentTimeMillis() - startTime; 27 | LogUtil.log("Loaded in %sms",String.valueOf(endTime)); 28 | 29 | }catch(Exception e){ 30 | LogUtil.err("Failed to load mappings data!"); 31 | LogUtil.err(e.getClass().getSimpleName() + " " + e.getMessage()); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/proguard/MappingReader.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings.proguard; 2 | 3 | import me.dickmeister.client.mappings.proguard.processor.MappingProcessor; 4 | 5 | import java.io.*; 6 | 7 | 8 | /** 9 | * This class can parse mapping files and invoke a processor for each of the 10 | * mapping entries. 11 | * 12 | * @author Eric Lafortune 13 | */ 14 | public class MappingReader 15 | { 16 | private final String mappingData; 17 | 18 | 19 | public MappingReader(String mappingFile) 20 | { 21 | this.mappingData = mappingFile; 22 | } 23 | 24 | 25 | /** 26 | * Reads the mapping file, presenting all of the encountered mapping entries 27 | * to the given processor. 28 | */ 29 | public void pump(MappingProcessor mappingProcessor) throws IOException 30 | { 31 | LineNumberReader reader = new LineNumberReader(new BufferedReader(new StringReader(mappingData))); 32 | try 33 | { 34 | String className = null; 35 | 36 | // Read the subsequent class mappings and class member mappings. 37 | while (true) 38 | { 39 | String line = reader.readLine(); 40 | 41 | if (line == null) 42 | { 43 | break; 44 | } 45 | 46 | line = line.trim(); 47 | 48 | // Is it a non-comment line? 49 | if (!line.startsWith("#")) 50 | { 51 | // Is it a class mapping or a class member mapping? 52 | if (line.endsWith(":")) 53 | { 54 | // Process the class mapping and remember the class's 55 | // old name. 56 | className = processClassMapping(line, mappingProcessor); 57 | } 58 | else if (className != null) 59 | { 60 | // Process the class member mapping, in the context of 61 | // the current old class name. 62 | processClassMemberMapping(className, line, mappingProcessor); 63 | } 64 | } 65 | } 66 | } 67 | catch (IOException ex) 68 | { 69 | throw new IOException("Can't process mapping file (" + ex.getMessage() + ")"); 70 | } 71 | finally 72 | { 73 | try 74 | { 75 | reader.close(); 76 | } 77 | catch (IOException ex) 78 | { 79 | // This shouldn't happen. 80 | } 81 | } 82 | } 83 | 84 | 85 | /** 86 | * Parses the given line with a class mapping and processes the 87 | * results with the given mapping processor. Returns the old class name, 88 | * or null if any subsequent class member lines can be ignored. 89 | */ 90 | private String processClassMapping(String line, 91 | MappingProcessor mappingProcessor) 92 | { 93 | // See if we can parse "___ -> ___:", containing the original 94 | // class name and the new class name. 95 | 96 | int arrowIndex = line.indexOf("->"); 97 | if (arrowIndex < 0) 98 | { 99 | return null; 100 | } 101 | 102 | int colonIndex = line.indexOf(':', arrowIndex + 2); 103 | if (colonIndex < 0) 104 | { 105 | return null; 106 | } 107 | 108 | // Extract the elements. 109 | String className = line.substring(0, arrowIndex).trim(); 110 | String newClassName = line.substring(arrowIndex + 2, colonIndex).trim(); 111 | 112 | // Process this class name mapping. 113 | boolean interested = mappingProcessor.processClassMapping(className, newClassName); 114 | 115 | return interested ? className : null; 116 | } 117 | 118 | 119 | /** 120 | * Parses the given line with a class member mapping and processes the 121 | * results with the given mapping processor. 122 | */ 123 | private void processClassMemberMapping(String className, 124 | String line, 125 | MappingProcessor mappingProcessor) 126 | { 127 | // See if we can parse one of 128 | // ___ ___ -> ___ 129 | // ___:___:___ ___(___) -> ___ 130 | // ___:___:___ ___(___):___ -> ___ 131 | // ___:___:___ ___(___):___:___ -> ___ 132 | // containing the optional line numbers, the return type, the original 133 | // field/method name, optional arguments, the optional original line 134 | // numbers, and the new field/method name. The original field/method 135 | // name may contain an original class name "___.___". 136 | 137 | int colonIndex1 = line.indexOf(':'); 138 | int colonIndex2 = colonIndex1 < 0 ? -1 : line.indexOf(':', colonIndex1 + 1); 139 | int spaceIndex = line.indexOf(' ', colonIndex2 + 2); 140 | int argumentIndex1 = line.indexOf('(', spaceIndex + 1); 141 | int argumentIndex2 = argumentIndex1 < 0 ? -1 : line.indexOf(')', argumentIndex1 + 1); 142 | int colonIndex3 = argumentIndex2 < 0 ? -1 : line.indexOf(':', argumentIndex2 + 1); 143 | int colonIndex4 = colonIndex3 < 0 ? -1 : line.indexOf(':', colonIndex3 + 1); 144 | int arrowIndex = line.indexOf("->", (colonIndex4 >= 0 ? colonIndex4 : 145 | colonIndex3 >= 0 ? colonIndex3 : 146 | argumentIndex2 >= 0 ? argumentIndex2 : 147 | spaceIndex) + 1); 148 | 149 | if (spaceIndex < 0 || 150 | arrowIndex < 0) 151 | { 152 | return; 153 | } 154 | 155 | // Extract the elements. 156 | String type = line.substring(colonIndex2 + 1, spaceIndex).trim(); 157 | String name = line.substring(spaceIndex + 1, argumentIndex1 >= 0 ? argumentIndex1 : arrowIndex).trim(); 158 | String newName = line.substring(arrowIndex + 2).trim(); 159 | 160 | // Does the method name contain an explicit original class name? 161 | String newClassName = className; 162 | int dotIndex = name.lastIndexOf('.'); 163 | if (dotIndex >= 0) 164 | { 165 | className = name.substring(0, dotIndex); 166 | name = name.substring(dotIndex + 1); 167 | } 168 | 169 | // Process this class member mapping. 170 | if (type.length() > 0 && 171 | name.length() > 0 && 172 | newName.length() > 0) 173 | { 174 | // Is it a field or a method? 175 | if (argumentIndex2 < 0) 176 | { 177 | mappingProcessor.processFieldMapping(className, 178 | type, 179 | name, 180 | newClassName, 181 | newName); 182 | } 183 | else 184 | { 185 | int firstLineNumber = 0; 186 | int lastLineNumber = 0; 187 | int newFirstLineNumber = 0; 188 | int newLastLineNumber = 0; 189 | 190 | if (colonIndex2 >= 0) 191 | { 192 | firstLineNumber = newFirstLineNumber = Integer.parseInt(line.substring(0, colonIndex1).trim()); 193 | lastLineNumber = newLastLineNumber = Integer.parseInt(line.substring(colonIndex1 + 1, colonIndex2).trim()); 194 | } 195 | 196 | if (colonIndex3 >= 0) 197 | { 198 | firstLineNumber = Integer.parseInt(line.substring(colonIndex3 + 1, colonIndex4 > 0 ? colonIndex4 : arrowIndex).trim()); 199 | lastLineNumber = colonIndex4 < 0 ? firstLineNumber : 200 | Integer.parseInt(line.substring(colonIndex4 + 1, arrowIndex).trim()); 201 | } 202 | 203 | String arguments = line.substring(argumentIndex1 + 1, argumentIndex2).trim(); 204 | 205 | mappingProcessor.processMethodMapping(className, 206 | firstLineNumber, 207 | lastLineNumber, 208 | type, 209 | name, 210 | arguments, 211 | newClassName, 212 | newFirstLineNumber, 213 | newLastLineNumber, 214 | newName); 215 | } 216 | } 217 | } 218 | } 219 | 220 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/proguard/objects/MappedClass.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings.proguard.objects; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class MappedClass { 7 | 8 | private final String className; //Original 9 | private final String newClassName; //Obfuscated 10 | private final Map mappedFieldMap = new HashMap<>(); 11 | private final Map mappedMethodMap = new HashMap<>(); 12 | 13 | public MappedClass(String className, String newClassName) { 14 | this.className = className; 15 | this.newClassName = newClassName; 16 | } 17 | 18 | public String getClassName() { 19 | return className; 20 | } 21 | 22 | public String getNewClassName() { 23 | return newClassName; 24 | } 25 | 26 | public Map getMappedFieldMap() { 27 | return mappedFieldMap; 28 | } 29 | 30 | public Map getMappedMethodMap() { 31 | return mappedMethodMap; 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/proguard/objects/MappedField.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings.proguard.objects; 2 | 3 | public class MappedField { 4 | 5 | private final String className; //Original 6 | private final String fieldName; //Original 7 | private final String fieldType; //No changes 8 | private final String newClassName; //Obfuscated 9 | private final String newFieldName; //Obfuscated 10 | 11 | public MappedField(String className, String fieldType, String fieldName, String newClassName, String newFieldName) { 12 | this.className = className; 13 | this.fieldName = fieldName; 14 | this.fieldType = fieldType; 15 | this.newClassName = newClassName; 16 | this.newFieldName = newFieldName; 17 | } 18 | 19 | public String getNewClassName() { 20 | return newClassName; 21 | } 22 | 23 | public String getClassName() { 24 | return className; 25 | } 26 | 27 | public String getFieldName() { 28 | return fieldName; 29 | } 30 | 31 | public String getFieldType() { 32 | return fieldType; 33 | } 34 | 35 | public String getNewFieldName() { 36 | return newFieldName; 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/proguard/objects/MappedMethod.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings.proguard.objects; 2 | 3 | public class MappedMethod { 4 | 5 | private final String className; //Original 6 | private final int firstLineNumber; //Original 7 | private final int lastLineNumber; //Original 8 | 9 | private final String methodReturnType; //No Changes 10 | private final String methodName; //Original 11 | private final String methodArguments; //No Changes 12 | 13 | private final String newClassName; //Obfuscated 14 | private final int newFirstLineNumber; //Obfuscated 15 | private final int newLastLineNumber; //Obfuscated 16 | private final String newMethodName; //Obfuscated 17 | 18 | public MappedMethod(String className, int firstLineNumber, int lastLineNumber, String methodReturnType, String methodName, String methodArguments, String newClassName, int newFirstLineNumber, int newLastLineNumber, String newMethodName) { 19 | this.className = className; 20 | this.firstLineNumber = firstLineNumber; 21 | this.lastLineNumber = lastLineNumber; 22 | this.methodReturnType = methodReturnType; 23 | this.methodName = methodName; 24 | this.methodArguments = methodArguments; 25 | this.newClassName = newClassName; 26 | this.newFirstLineNumber = newFirstLineNumber; 27 | this.newLastLineNumber = newLastLineNumber; 28 | this.newMethodName = newMethodName; 29 | } 30 | 31 | public int getFirstLineNumber() { 32 | return firstLineNumber; 33 | } 34 | 35 | public int getLastLineNumber() { 36 | return lastLineNumber; 37 | } 38 | 39 | public int getNewFirstLineNumber() { 40 | return newFirstLineNumber; 41 | } 42 | 43 | public int getNewLastLineNumber() { 44 | return newLastLineNumber; 45 | } 46 | 47 | public String getClassName() { 48 | return className; 49 | } 50 | 51 | public String getMethodArguments() { 52 | return methodArguments; 53 | } 54 | 55 | public String getMethodName() { 56 | return methodName; 57 | } 58 | 59 | public String getMethodReturnType() { 60 | return methodReturnType; 61 | } 62 | 63 | public String getNewClassName() { 64 | return newClassName; 65 | } 66 | 67 | public String getNewMethodName() { 68 | return newMethodName; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/proguard/processor/MappingProcessor.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings.proguard.processor; 2 | 3 | public interface MappingProcessor 4 | { 5 | /** 6 | * Processes the given class name mapping. 7 | * 8 | * @param className the original class name. 9 | * @param newClassName the new class name. 10 | * @return whether the processor is interested in receiving mappings of the 11 | * class members of this class. 12 | */ 13 | public boolean processClassMapping(String className, 14 | String newClassName); 15 | 16 | /** 17 | * Processes the given field name mapping. 18 | * @param className the original class name. 19 | * @param fieldType the original external field type. 20 | * @param fieldName the original field name. 21 | * @param newClassName the new class name. 22 | * @param newFieldName the new field name. 23 | */ 24 | public void processFieldMapping(String className, 25 | String fieldType, 26 | String fieldName, 27 | String newClassName, 28 | String newFieldName); 29 | 30 | /** 31 | * Processes the given method name mapping. 32 | * @param className the original class name. 33 | * @param firstLineNumber the first line number of the method, or 0 if 34 | * it is not known. 35 | * @param lastLineNumber the last line number of the method, or 0 if 36 | * it is not known. 37 | * @param methodReturnType the original external method return type. 38 | * @param methodName the original external method name. 39 | * @param methodArguments the original external method arguments. 40 | * @param newClassName the new class name. 41 | * @param newFirstLineNumber the new first line number of the method, or 0 42 | * if it is not known. 43 | * @param newLastLineNumber the new last line number of the method, or 0 44 | * if it is not known. 45 | * @param newMethodName the new method name. 46 | */ 47 | public void processMethodMapping(String className, 48 | int firstLineNumber, 49 | int lastLineNumber, 50 | String methodReturnType, 51 | String methodName, 52 | String methodArguments, 53 | String newClassName, 54 | int newFirstLineNumber, 55 | int newLastLineNumber, 56 | String newMethodName); 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/proguard/processor/impl/ClientMappingProcessor.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings.proguard.processor.impl; 2 | 3 | import me.dickmeister.client.mappings.MappingManager; 4 | import me.dickmeister.client.mappings.proguard.objects.MappedClass; 5 | import me.dickmeister.client.mappings.proguard.objects.MappedField; 6 | import me.dickmeister.client.mappings.proguard.objects.MappedMethod; 7 | import me.dickmeister.client.mappings.proguard.processor.MappingProcessor; 8 | import me.dickmeister.client.mappings.proguard.utils.ProguardMap; 9 | import me.dickmeister.common.util.LogUtil; 10 | 11 | import java.util.Objects; 12 | 13 | public class ClientMappingProcessor implements MappingProcessor { 14 | 15 | private final MappingManager mappingManager; 16 | 17 | public ClientMappingProcessor(MappingManager mappingManager) { 18 | this.mappingManager = mappingManager; 19 | } 20 | 21 | @Override 22 | public boolean processClassMapping(String className, String newClassName) { 23 | if(mappingManager.getMappedClasses().containsKey(className)) return true; 24 | 25 | mappingManager.getMappedClasses().put(className,new MappedClass(className,newClassName)); 26 | return true; 27 | } 28 | 29 | @Override 30 | public void processFieldMapping(String className, String fieldType, String fieldName, String newClassName, String newFieldName) { 31 | var mappedClass = mappingManager.getMappedClasses().get(className); 32 | if(Objects.isNull(mappedClass)){ 33 | processClassMapping(className,newClassName); 34 | processFieldMapping(className,fieldType,fieldName,newClassName,newFieldName); 35 | return; 36 | } 37 | 38 | var fieldMap = mappedClass.getMappedFieldMap(); 39 | if(fieldMap.containsKey(fieldName)){ 40 | LogUtil.err("Found duplicate field entry in class " + className + " fieldName: " + fieldName); 41 | return; 42 | } 43 | fieldMap.put(fieldName,new MappedField(className,fieldType,fieldName,newClassName,newFieldName)); 44 | } 45 | 46 | @Override 47 | public void processMethodMapping(String className, int firstLineNumber, int lastLineNumber, String methodReturnType, String methodName, String methodArguments, String newClassName, int newFirstLineNumber, int newLastLineNumber, String newMethodName) { 48 | var mappedClass = mappingManager.getMappedClasses().get(className); 49 | if(Objects.isNull(mappedClass)){ 50 | processClassMapping(className,newClassName); 51 | processMethodMapping(className,firstLineNumber,lastLineNumber,methodReturnType,methodName,methodArguments,newClassName,newFirstLineNumber,newLastLineNumber,newMethodName); 52 | return; 53 | } 54 | 55 | var methodMap = mappedClass.getMappedMethodMap(); 56 | var originalDesc = methodName + ProguardMap.fromProguardSignature('(' + methodArguments + ')' + methodReturnType); 57 | if (methodMap.containsKey(originalDesc)) { 58 | LogUtil.err("Found duplicate method entry in class " + className + " methodName: " + methodName); 59 | return; 60 | } 61 | methodMap.put(originalDesc,new MappedMethod(className,firstLineNumber,lastLineNumber,methodReturnType,methodName,methodArguments,newClassName,newFirstLineNumber,newLastLineNumber,newMethodName)); 62 | 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/mappings/proguard/utils/ProguardMap.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.mappings.proguard.utils; 2 | 3 | import me.dickmeister.common.util.LogUtil; 4 | 5 | public class ProguardMap { 6 | 7 | // Converts a proguard-formatted method signature into a Java formatted 8 | // method signature. 9 | public static String fromProguardSignature(String sig) { 10 | if (sig.startsWith("(")) { 11 | int end = sig.indexOf(')'); 12 | if (end == -1) { 13 | LogUtil.err("Error parsing signature: " + sig); 14 | } 15 | 16 | StringBuilder converted = new StringBuilder(); 17 | converted.append('('); 18 | if (end > 1) { 19 | for (String arg : sig.substring(1, end).split(",")) { 20 | converted.append(fromProguardSignature(arg)); 21 | } 22 | } 23 | converted.append(')'); 24 | converted.append(fromProguardSignature(sig.substring(end + 1))); 25 | return converted.toString(); 26 | } else if (sig.endsWith("[]")) { 27 | return "[" + fromProguardSignature(sig.substring(0, sig.length() - 2)); 28 | } else if (sig.equals("boolean")) { 29 | return "Z"; 30 | } else if (sig.equals("byte")) { 31 | return "B"; 32 | } else if (sig.equals("char")) { 33 | return "C"; 34 | } else if (sig.equals("short")) { 35 | return "S"; 36 | } else if (sig.equals("int")) { 37 | return "I"; 38 | } else if (sig.equals("long")) { 39 | return "J"; 40 | } else if (sig.equals("float")) { 41 | return "F"; 42 | } else if (sig.equals("double")) { 43 | return "D"; 44 | } else if (sig.equals("void")) { 45 | return "V"; 46 | } else { 47 | return "L" + sig.replace('.', '/') + ";"; 48 | } 49 | } 50 | 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/tasks/TickingTask.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.tasks; 2 | 3 | import com.darkmagician6.eventapi.EventManager; 4 | import me.dickmeister.client.core.event.impl.ClientInternalTickEvent; 5 | 6 | public class TickingTask implements Runnable{ 7 | @Override 8 | public void run() { 9 | EventManager.call(new ClientInternalTickEvent()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/transformers/TestTransformer.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.transformers; 2 | 3 | import javassist.*; 4 | import me.dickmeister.client.ClientMain; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.IOException; 8 | import java.lang.instrument.ClassFileTransformer; 9 | import java.lang.instrument.IllegalClassFormatException; 10 | import java.security.ProtectionDomain; 11 | 12 | public class TestTransformer implements ClassFileTransformer { 13 | 14 | @Override 15 | public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { 16 | var clazz = ClientMain.getMappingManager().translateClassName("net.minecraft.world.entity.player.Player") + "$1"; 17 | 18 | System.out.println("PreReformatting: " + className + " looking for " + clazz); 19 | if(!className.equals(clazz)) 20 | return classfileBuffer; 21 | 22 | try { 23 | System.out.println("Reformatting: " + className); 24 | ClassPool classPool = ClassPool.getDefault(); 25 | classPool.appendClassPath(new LoaderClassPath(loader)); 26 | 27 | CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer)); 28 | // modyfikujesz sobie cos w tej klasie 29 | var methodName = ClientMain.getMappingManager() 30 | .translateMethodName("net.minecraft.world.entity.player.Player", 31 | "getDimensions(Lnet/minecraft/world/entity/Pose;)Lnet/minecraft/world/entity/EntityDimensions;"); 32 | CtMethod m = ctClass.getDeclaredMethod(methodName); 33 | m.insertBefore("{ System.out.println($1); }"); 34 | 35 | classfileBuffer = ctClass.toBytecode(); 36 | ctClass.detach(); 37 | 38 | return classfileBuffer; 39 | } catch (IOException | CannotCompileException ex) { 40 | ex.printStackTrace(); 41 | System.exit(-1); 42 | return classfileBuffer; 43 | } catch (NotFoundException e) { 44 | e.printStackTrace(); 45 | return classfileBuffer; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/version/VersionFinder.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.version; 2 | 3 | import me.dickmeister.client.version.component.VersionFinderComponent; 4 | import me.dickmeister.client.version.component.impl.LatestFinderComponent; 5 | import me.dickmeister.common.util.LogUtil; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class VersionFinder { 11 | private final Map componentMap = new HashMap<>(); 12 | 13 | { 14 | //Initialize components 15 | componentMap.put("latest",new LatestFinderComponent()); 16 | } 17 | 18 | /** 19 | * Feeding all the components to find the version that client is running on currently! 20 | */ 21 | public ClientVersion findVersion(){ 22 | for(var key : componentMap.keySet()){ 23 | var component = componentMap.get(key); 24 | 25 | LogUtil.log("Attempting to search for version using component: %s",key); 26 | var version = component.search(); 27 | 28 | if(version != null) { 29 | LogUtil.log("Found client version name: %s",version.getVersion()); 30 | LogUtil.log("Found client protocol identifier: %s", String.valueOf(version.getProtocol())); 31 | return version; 32 | } 33 | } 34 | 35 | return null; 36 | } 37 | 38 | /** 39 | * Client version holding class 40 | */ 41 | public static class ClientVersion { 42 | 43 | private final String VERSION_STRING; 44 | private final int RELEASE_NETWORK_PROTOCOL_VERSION; 45 | private final boolean SNAPSHOT; 46 | 47 | public ClientVersion(String version_string, int release_network_protocol_version, boolean snapshot) { 48 | VERSION_STRING = version_string; 49 | RELEASE_NETWORK_PROTOCOL_VERSION = release_network_protocol_version; 50 | SNAPSHOT = snapshot; 51 | } 52 | 53 | public int getProtocol() { 54 | return RELEASE_NETWORK_PROTOCOL_VERSION; 55 | } 56 | 57 | public String getVersion() { 58 | return VERSION_STRING; 59 | } 60 | 61 | public boolean isSnapshot() { 62 | return SNAPSHOT; 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/version/component/VersionFinderComponent.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.version.component; 2 | 3 | import me.dickmeister.client.version.VersionFinder; 4 | 5 | public abstract class VersionFinderComponent { 6 | 7 | public abstract VersionFinder.ClientVersion search(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/client/version/component/impl/LatestFinderComponent.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.client.version.component.impl; 2 | 3 | import me.dickmeister.client.version.VersionFinder; 4 | import me.dickmeister.client.version.component.VersionFinderComponent; 5 | 6 | public class LatestFinderComponent extends VersionFinderComponent { 7 | 8 | @Override 9 | public VersionFinder.ClientVersion search() { 10 | try { 11 | var sharedConstants = Class.forName("ab"); //net.minecraft.SharedConstants 12 | var versionField = sharedConstants.getDeclaredField("d"); //java.lang.String VERSION_STRING 13 | var protocolField = sharedConstants.getDeclaredField("f"); //int RELEASE_NETWORK_PROTOCOL_VERSION 14 | var snapshotField = sharedConstants.getDeclaredField("a"); //boolean SNAPSHOT 15 | 16 | var version = (String)versionField.get(null); 17 | var protocol = (int)protocolField.get(null); 18 | var snapshot = (boolean)snapshotField.get(null); 19 | 20 | if(snapshot) { 21 | return new VersionFinder.ClientVersion(version,protocol, true); 22 | } 23 | 24 | return new VersionFinder.ClientVersion(version,protocol, false); 25 | }catch(Exception e){ 26 | return null; 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/common/util/LogUtil.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.common.util; 2 | 3 | import me.dickmeister.client.ClientMain; 4 | 5 | public class LogUtil { 6 | 7 | public static void log(String msg, Object... args){ 8 | if(!ClientMain.DEBUG) return; 9 | System.out.println(String.format(msg, args)); 10 | } 11 | 12 | public static void err(String msg, Object... args){ 13 | if(!ClientMain.DEBUG) return; 14 | System.err.println(String.format(msg, args)); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/common/util/URLUtils.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.common.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.Reader; 7 | import java.net.URL; 8 | import java.nio.charset.StandardCharsets; 9 | 10 | public class URLUtils { 11 | 12 | public static String readAllFromUrl(String url) throws Exception{ 13 | try (var is = new URL(url).openStream()) { 14 | var reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); 15 | return readAll(reader); 16 | } 17 | } 18 | 19 | public static String readAll(Reader rd) throws IOException { 20 | StringBuilder sb = new StringBuilder(); 21 | int cp; 22 | while ((cp = rd.read()) != -1) { 23 | sb.append((char) cp); 24 | } 25 | return sb.toString(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/me/dickmeister/injector/ClientInjector.java: -------------------------------------------------------------------------------- 1 | package me.dickmeister.injector; 2 | 3 | import com.sun.tools.attach.VirtualMachine; 4 | import com.sun.tools.attach.VirtualMachineDescriptor; 5 | import me.dickmeister.agent.ClientAgent; 6 | import me.dickmeister.agent.attacher.AgentAttacher; 7 | 8 | import java.util.List; 9 | import java.util.Scanner; 10 | 11 | public class ClientInjector { 12 | 13 | public static void main(String[] args) { 14 | List descriptors = VirtualMachine.list(); 15 | 16 | System.out.println("[Injector] List of running VMs:"); 17 | var index = 0; 18 | for (VirtualMachineDescriptor descriptor : descriptors) { 19 | var printer = System.out; 20 | if(descriptor.displayName().contains("net.minecraft.client.main.Main") || descriptor.displayName().contains("net.fabricmc")) printer = System.err; 21 | 22 | printer.println(" #" + ++index + " > " + descriptor.id() + " " + descriptor.displayName().split(" ")[0]); 23 | } 24 | 25 | System.out.print("[Injector] Select one of the above VMs to attach to: "); 26 | var scanner = new Scanner(System.in); 27 | var input = scanner.nextLine(); 28 | 29 | var vmIndex = Integer.parseInt(input); 30 | var vm = descriptors.get(vmIndex - 1); 31 | System.out.println("[Injector] Selected VM: " + vm.id()); 32 | 33 | var agentPath = ClientInjector.class.getProtectionDomain().getCodeSource().getLocation().getPath() 34 | .replace("/","\\") 35 | .substring(1); 36 | 37 | System.out.println("[Injector] Attaching from: " + agentPath); 38 | 39 | try { 40 | AgentAttacher.attachDynamic(agentPath, vm.id()); 41 | System.out.println("[Injector] Attached!"); 42 | }catch(Exception e){ 43 | e.printStackTrace(); 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: me.dickmeister.injector.ClientInjector 3 | Agent-Class: me.dickmeister.agent.ClientAgent 4 | Can-Redefine-Classes: true 5 | Can-Retransform-Classes: true 6 | Can-Set-Native-Method-Prefix: true 7 | Permissions: all-permissions 8 | 9 | -------------------------------------------------------------------------------- /src/test/java/AttachTest.java: -------------------------------------------------------------------------------- 1 | import me.dickmeister.agent.attacher.AgentAttacher; 2 | 3 | public class AttachTest { 4 | 5 | public static void main(String[] args) throws Exception { 6 | var path = "C:\\Users\\dickmeister\\Desktop\\Projekty\\InjectionClientTest\\out\\artifacts\\InjectionClientTest_jar\\InjectClient.jar"; 7 | AgentAttacher.attachDynamic(path,"6824"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/MappingPrinter.java: -------------------------------------------------------------------------------- 1 | import me.dickmeister.client.mappings.MappingManager; 2 | import me.dickmeister.client.mappings.VersionMappingsLoader; 3 | import me.dickmeister.client.mappings.loader.MappingsLoader; 4 | import me.dickmeister.client.version.VersionFinder; 5 | 6 | public class MappingPrinter { 7 | 8 | public static void main(String[] args) { 9 | var version = new VersionFinder.ClientVersion("1.18",761,false); 10 | var mappingManager = new MappingManager(); 11 | 12 | var mappingsLoader = new MappingsLoader(mappingManager); 13 | var mappingsUrl = new VersionMappingsLoader().loadFromVersion(version); 14 | mappingsLoader.loadFromUrl(mappingsUrl); 15 | 16 | var mappings = mappingManager.getMappedClasses(); 17 | mappings.forEach((key,clazz) -> { 18 | if(!key.startsWith("net.minecraft.world.entity.player.Player")) return; 19 | System.out.println(key + " " + clazz.getNewClassName()); 20 | clazz.getMappedFieldMap().forEach((fieldKey,field) -> { 21 | System.out.println("\t" + fieldKey + " " + field.getNewFieldName()); 22 | }); 23 | clazz.getMappedMethodMap().forEach((method,mappedMethod) -> { 24 | System.out.println("\t" + method + " " + mappedMethod.getNewMethodName()); 25 | }); 26 | }); 27 | } 28 | 29 | } 30 | --------------------------------------------------------------------------------