How to code your hacks PROPERLY
DISCLAIMER:
This tutorial is provided by godshawk "as is" and "with all faults." godshawk makes no representations or warranties of any kind concerning the safety, suitability, lack of viruses, inaccuracies, typographical errors, or other harmful components of this tutorial. There are inherent dangers in the use of any software, and you are solely responsible for determining whether this tutorial is compatible with your equipment and other software installed on your equipment, as well as your Java knowledge. You are also solely responsible for the protection of your equipment and backup of your data, and godshawk will not be liable for any damages you may suffer in connection with using, modifying, or distributing this tutorial/code/etc.
IF YOU DO NOT KNOW BASICS OF JAVA SUCH AS ANNOTATIONS, INHERITANCE, OBJECT-ORIENTED PROGRAMMING, AND THE LIKE, THEN THIS TUTORIAL IS NOT FOR YOU. LEAVE NOW. THIS TUTORIAL IS NOT A JAVA TUTORIAL; IT IS A CLIENT-MAKING TUTORIAL. THE CODE SAMPLES PROVIDED IN THIS TUTORIAL HAVE NO GUARANTEE OF WORKING. COMMENTS ARE PROVIDED, BUT MAY OR MAY NOT TELL THE ENTIRE STORY. YOU HAVE BEEN WARNED.
Right, so I've been gone for a while, learned a TON about Java, and so on. So Imma teach y'all about it.
'Kay, so first, you need a main class. To start, it'll look like this:
Code:
package com.luna.inkaria.core;
public final class Inkaria {
// Singleton instance
private static volatile Inkaria instance;
private Inkaria() {
// Stuff will go here later.
}
// Returns the singleton instance of this class
public static Inkaria getInstance() {
if(instance == null) {
instance = new Inkaria();
}
return instance;
}
}
This is the base logger. It defines the behavior that the classes that extend it will take.
Code:
package com.luna.lib.loggers;
import com.luna.lib.loggers.enums.EnumLogType;
/**
* The base of all loggers
*/
public abstract class AbstractLogger {
// Logs the message at the default log level
public void log(final Object data) {
this.log(EnumLogType.INFO, data);
}
// Logs at the specified level
public abstract void log(EnumLogType level, Object data);
}
Code:
package com.luna.lib.loggers;
import com.luna.lib.loggers.enums.EnumLogType;
public class BasicLogger extends AbstractLogger {
// Dat singleton. We *could* just have static methods, but where's the fun in that? This is my
// code, I'll have it how I like ;)
private static final BasicLogger instance = new BasicLogger();
@Override
public void log(final EnumLogType level, final Object data) {
System.out.println(String.format("[%s] %s", level.getName(), data.toString()));
}
public static BasicLogger getInstance() {
return instance;
}
}
Code:
package com.luna.inkaria.loggers;
import com.luna.lib.loggers.BasicLogger;
import com.luna.lib.loggers.enums.EnumLogType;
/**
* Logger for the client
*
* @author godshawk
*
*/
public class InkariaLogger extends BasicLogger {
private static final InkariaLogger instance = new InkariaLogger();
@Override
public void log(final EnumLogType level, final Object data) {
System.out.println(String.format("[Inkaria] [%s] %s", level.getName(), data.toString()));
}
public static final InkariaLogger getInstance() {
return instance;
}
}
Finally, we need the enum that holds the different log levels:
Code:
package com.luna.lib.loggers.enums;
import com.luna.lib.util.string.StringUtil;
/**
* An enum of all the log "levels".
*/
public enum EnumLogType {
/**
* Information
*/
INFO,
/**
* Warning
*/
WARNING,
/**
* Total wipeout
*/
FATAL,
/**
* Stacktrace
*/
TRACE,
/**
* Hooking (a) class(es)
*/
HOOK,
/**
* Scanning, either the JAR or elsewhere
*/
SCAN,
/**
* Debug info
*/
DEBUG,
/**
* Woot! Werk'd!
*/
SUCCESS,
/**
* Just for IO
*/
IO;
/**
* Returns the name of the Enum object capitalized properly; eg. "INFO"
* becomes "Info".
*
* @return
*/
public final String getName() {
return StringUtil.capitalize(name()).trim();
}
}
Code:
package com.luna.lib.util.string;
import java.util.Random;
/**
* String-related utilities
*
* @author godshawk
*
*/
public class StringUtil {
/**
* All the standard ASCII alphanumeric characters
*/
private static final char[] ALPHANUM = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'
};
/**
* All the consonants, both cases.
*/
private static final char[] CONSONANTS = new char[] {
'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v',
'w', 'x', 'z', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
'S', 'T', 'V', 'W', 'X', 'Z'
};
/**
* RNG
*/
private static final Random rand = new Random();
/**
* Generates a random <code>String</code> of up to 10 characters
*
* @see {@link StringUtil#genRandomString(int)}
* @return {@link StringUtil#genRandomString(int)}
*/
public static String genRandomString() {
return genRandomString(rand.nextInt(10));
}
/**
* Generates a random <code>String</code> of the specified length
*
* @param len
* Length of the String
* @return Random String
*/
public static String genRandomString(final int len) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++) {
final char c = ALPHANUM[rand.nextInt(ALPHANUM.length)];
sb.append(c);
}
return sb.toString();
}
/**
* Returns true if <code>in</code> contains <code>out</code>.
*
* @param in
* @param check
* @return
*/
public static boolean doesStringContain(final String in, final String check) {
final boolean out = in.toLowerCase().contains(check.toLowerCase());
return out;
}
/**
* Like Python's String.join()
*
* @param strings
* @return
*/
public static String join(final String[] strings) {
return join(", ", strings);
}
/**
* Like Python's String.join()
*
* @param joiner
* @param strings
* @return
*/
public static String join(final String joiner, final String[] strings) {
String res = "";
for (final String e : strings) {
if (e.length() > 0) {
res += e + joiner;
}
}
return res.substring(0, res.length() - 2);
}
public static String addED(final String in) {
final char end = in.charAt(in.length() - 1);
String out = in;
if (charArrayContains(end, CONSONANTS)) {
out += ((new Character(end)).toString());
out += "ed";
} else if (new Character(end).equals('y')) {
out = in.substring(0, in.length() - 1) + "ied";
} else if (new Character(end).equals('e')) {
out += "d";
} else {
out += "ed";
}
return out;
}
/**
* Returns true if the char[], <code>f</code>, contains the input char,
* <code>e</code>.
*
* @param e
* @param f
* @return
*/
private static boolean charArrayContains(final char e, final char[] f) {
for (final char z : f) {
if (e == z) {
return true;
}
}
return false;
}
public static String capitalize(final String in) {
return in.substring(0, 1).toUpperCase().concat(in.substring(1).toLowerCase());
}
}
NOTE: THIS SECTION ASSUMES THAT YOU ALREADY KNOW WHAT EVENTS ARE
Okay, so first, we need our base event class. It looks like this:
Code:
package com.luna.lib.event;
/**
* Base of all events
*
* @author godshawk
*
*/
public abstract class EventBase {
/**
* Class the event originated from
*/
private final Object source;
/**
* Constructor
*
* @param source
*/
public EventBase(final Object source) {
this.source = source;
}
/**
* Returns the class that this event was called from
*
* @return
*/
public final Object getSource() {
return source;
}
}
Optional: Cancellable events
Events can be canceled (Say, chat events...), so we need a class for that. It'd look like this:
Code:
package com.luna.lib.event;
/**
* If an event can be cancelled, ie for things like Freecam, the event would
* have to extend this class.
*
* @author godshawk
*
*/
public abstract class EventCancellable extends EventBase {
private boolean isCancelled = false;
public EventCancellable(final Object source) {
super(source);
// TODO Auto-generated constructor stub
}
public void cancel() {
isCancelled = true;
}
public boolean getCancelled() {
return isCancelled;
}
}
Naturally, we're going to have a class that 'handles' all the events; ie sends them out to the listeners. But first, there's one more essential component that we're missing: The EventListener annotation. It'll look like this:
Code:
package com.luna.lib.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.luna.lib.event.EventBase;
import com.luna.lib.event.enums.EnumEventPriority;
/**
* Tells the EventManager that the given method handles Events.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface EventListener {
Class<? extends EventBase> event();
EnumEventPriority priority() default EnumEventPriority.NORMAL;
}
Code:
@EventListener(event = MyCustomEvent.class, priority = EnumEventPriority.HIGHEST)
public void foo(Bar bar) {}
Code:
package com.luna.lib.event.enums;
/**
* EventListeners, how important are you?
*
* @author godshawk
*
*/
public enum EnumEventPriority {
/**
* Event is of the <strong>lowest</strong> priority
*/
LOWEST,
/**
* Event is more important than <code>LOWEST</code>, but still low priority
*/
LOW,
/**
* Event is middle priority
*/
NORMAL,
/**
* Event is important
*/
HIGH,
/**
* Event is the most important
*/
HIGHEST;
}
Code:
package com.luna.lib.handlers.event;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.luna.lib.annotations.EventListener;
import com.luna.lib.event.EventBase;
import com.luna.lib.event.enums.EnumEventPriority;
/**
*
* @author godshawk
*
* @update Updated so that the annotations specify the priority
*
*/
public final class EventManager {
/**
* Singleton
*/
private static volatile EventManager instance = new EventManager();
/**
* Map of classes that contain "event listener" methods.
*/
private volatile Map<Object, LinkedList<Method>> eventListeners;
/**
* Since there will only ever be one instance of it, there is no reason for
* this to be public
*/
private EventManager() {
eventListeners = new ConcurrentHashMap<Object, LinkedList<Method>>();
eventListeners.clear();
}
/**
* Returns the singleton instance of the EventManager
*
* @return
*/
public static final EventManager getInstance() {
return instance;
}
/**
* Adds a listener.
*
* @param o
*/
public final void addListener(final Object o) {
final Method[] declared = o.getClass().getDeclaredMethods();
final LinkedList<Method> listeners = new LinkedList<Method>();
for (final Method e : declared) {
if (e.isAnnotationPresent(EventListener.class)) {
listeners.add(e);
}
}
synchronized (eventListeners) {
eventListeners.put(o, listeners);
}
}
/**
* Removes a listener.
*
* @param o
*/
public final void removeListener(final Object o) {
synchronized (eventListeners) {
for (final Map.Entry<Object, LinkedList<Method>> e : eventListeners.entrySet()) {
if (e.getKey().equals(o)) {
eventListeners.remove(e.getKey());
}
}
}
}
/**
* Returns the map of listeners
*
* @return
*/
public final Map<Object, LinkedList<Method>> getEventListeners() {
synchronized (eventListeners) {
return eventListeners;
}
}
/**
* Sends out an event
*
* @param event
*/
public final void fire(final EventBase event) {
// Synchronize synchronize synchronize!
synchronized (eventListeners) {
// Iterate through EventPriorities
for (final EnumEventPriority pr : EnumEventPriority.values()) {
// Iterate through map of listeners
for (final Map.Entry<Object, LinkedList<Method>> e : getEventListeners().entrySet()) {
// Get the list of event-listening methods in the class
final List<Method> f = e.getValue();
// Iterate through methods
for (final Method g : f) {
// For each String in the annotations parameters
// If the String is equal to the event's name
final EventListener h = g.getAnnotation(EventListener.class);
if (h.event().equals(event.getClass())) {
// Check for the priority
if (!h.priority().equals(pr)) {
continue;
}
// Make the method accessible
g.setAccessible(true);
// Attempt to invoke it, log the error if it
// fails
try {
// If there's no parameters for the method,
// just invoke it.
if (g.getParameterAnnotations().length == 0) {
g.invoke(e.getKey());
}
// If the method DOES have a parameter,
// invoke it and pass in the event as the
// parameter.
if (g.getParameterAnnotations().length == 1) {
g.invoke(e.getKey(), event);
}
} catch (final IllegalAccessException | InvocationTargetException e1) {
// Error logging
e1.printStackTrace();
}
}
}
}
}
}
}
}
The EventManager has a singleton instance of itself. This is so that you can do EventManager#getInstance() to use it.
It has a Map<Object, LinkedList<Method>> that stores the event listeners. This Map holds the Object that has been registered as the event listener (So we can invoke the methods), and a List<Method> of all the methods in the class that have our EventListener annotation on them. This is VERY important. This Map is instantiated as a ConcurrentHashMap because it can and will be accessed from multiple Threads.
The addListener method is simple. It gets the list of methods in the class using Reflection. It iterates through the methods. If the method is annotated with our EventListener annotation, it gets added to the LinkedList that will be put into the Map. Finally, it adds the Object and the corresponding List<Method> to the Map.
The removeListener method is even simpler. It just iterates through the Map. If it finds the listener, it removes it.
I'm just gonna gloss over the method where events are actually sent to the listeners, because it's commented well enough.
Okay, we have our Event system. Now what? We need to make our Modules, of course!
You have an abstract class as your base module; it should look something like this:
Code:
package com.luna.inkaria.module;
import java.util.LinkedList;
import java.util.List;
import com.luna.inkaria.events.EventAlert;
import net.minecraft.src.Entity;
import net.minecraft.src.EntityClientPlayerMP;
import net.minecraft.src.EntityLiving;
import net.minecraft.src.EntityPlayer;
import net.minecraft.src.EntityRenderer;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.Minecraft;
import net.minecraft.src.NetClientHandler;
import net.minecraft.src.Packet;
import net.minecraft.src.Packet3Chat;
import net.minecraft.src.PlayerControllerMP;
import net.minecraft.src.TileEntity;
import net.minecraft.src.Timer;
import net.minecraft.src.World;
import com.luna.inkaria.console.BaseCommand;
import com.luna.inkaria.console.ModCommand;
import com.luna.inkaria.core.Inkaria;
import com.luna.inkaria.events.EventRender3D;
import com.luna.inkaria.events.EventTick;
import com.luna.inkaria.gui.util.ChatColor;
import com.luna.inkaria.handlers.console.ConsoleManager;
import com.luna.inkaria.handlers.module.ModuleManager;
import com.luna.inkaria.hooks.HookEntityRenderer;
import com.luna.inkaria.loggers.ChatLogger;
import com.luna.inkaria.module.enums.EnumHackType;
import com.luna.lib.annotations.EventListener;
import com.luna.lib.annotations.TestClass;
import com.luna.lib.event.enums.EnumEventPriority;
import com.luna.lib.handlers.event.EventManager;
import com.luna.lib.loggers.enums.EnumLogType;
/**
* Base of all Modules
*
* @author godshawk
*
*/
public abstract class Module {
private int key;
private final String name, desc;
private boolean state;
private final EnumHackType type;
public Module() {
this("Test", "Test");
}
public Module(final String name, final String desc) {
this(name, desc, -1);
}
public Module(final String name, final String desc, final int key) {
this(name, desc, key, EnumHackType.PLAYER);
}
public Module(final String name, final String desc, final EnumHackType type) {
this(name, desc, -1, type);
}
public Module(final String name, final String desc, final int key, final EnumHackType type) {
this.name = name;
this.desc = desc;
this.key = key;
this.type = type;
}
/*
* There is absolutely NO REASON for those two to be abstract
*/
protected void onEnable() {
};
protected void onDisable() {
};
public final void toggle() {
state = !state;
if (state) {
if (getWorld() != null) {
onEnable();
}
EventManager.getInstance().addListener(this);
} else {
if (getWorld() != null) {
onDisable();
}
EventManager.getInstance().removeListener(this);
}
}
public final void setActive(final boolean state) {
this.state = state;
}
public final boolean getActive() {
return state;
}
public final String getName() {
return name;
}
public final String getDesc() {
return desc;
}
public final int getKey() {
return key;
}
public final void setKey(final int k) {
key = k;
}
/**
* 'Ticks' the module. The EventTick that is sent to this is called from
* {@link Minecraft#runGameLoop()}. It could be called from
* {@link Minecraft#runTick()}, but it's not.
*
* @see {@link Minecraft#runGameLoop()}
* @see {@link EventTick}
* @see {@link Inkaria#tick()}
*/
@Override
@EventListener(event = EventTick.class, priority = EnumEventPriority.HIGH)
public abstract void tick();
/**
* Renders the module. The EventRender3D that is used for calling this
* method is called from {@link EntityRenderer#renderHand(par1, par2)}.
* <strong>Technically</strong>, this is called from
* {@link HookEntityRenderer#renderHand(par1, par2)}.
*/
@Override
@EventListener(event = EventRender3D.class, priority = EnumEventPriority.HIGH)
public abstract void render();
public final EnumHackType getType() {
return type;
}
protected static final EntityClientPlayerMP getPlayer() {
return getMinecraft().thePlayer;
}
protected static final Minecraft getMinecraft() {
return Minecraft.getMinecraft();
}
protected static final World getWorld() {
return getMinecraft().theWorld;
}
protected static final List<TileEntity> getTileEntitiesInWorld() {
return getWorld().loadedTileEntityList;
}
protected static final List<EntityPlayer> getPlayersInWorld() {
return getWorld().playerEntities;
}
protected static final void displayGuiScreen(final GuiScreen e) {
getMinecraft().displayGuiScreen(e);
}
protected static final void sendPacket(final Packet packet) {
getSendQueue().addToSendQueue(packet);
}
protected static final void sendChatMessage(final String message) {
sendPacket(new Packet3Chat(message));
}
protected static final NetClientHandler getSendQueue() {
return getPlayer().sendQueue;
}
protected static final double getDistanceToEntity(final Entity e) {
return getPlayer().getDistanceToEntity(e);
}
protected static final double getDistanceSqToEntity(final Entity e) {
return getPlayer().getDistanceSqToEntity(e);
}
protected static final List<Entity> getLoadedEntities() {
return getWorld().loadedEntityList;
}
protected static final EntityRenderer getEntityRenderer() {
return getMinecraft().entityRenderer;
}
protected static final PlayerControllerMP getPlayerController() {
return getMinecraft().playerController;
}
protected static final boolean getCanEntityBeSeen(final Entity e) {
return getPlayer().canEntityBeSeen(e);
}
protected static final Timer getTimer() {
return getMinecraft().timer;
}
protected static final List<Entity> getEntitiesInRange(final double range) {
final List<Entity> list = new LinkedList<Entity>();
for (final Entity e : getLoadedEntities()) {
if (getDistanceToEntity(e) <= range) {
if (e instanceof EntityLiving) {
list.add(e);
} else {
continue;
}
} else {
// Totally useless :D
continue;
}
}
return list;
}
}

Obviously, you need the enum for hack types; here it is:
Code:
package com.luna.inkaria.module.enums;
import com.luna.inkaria.gui.util.ChatColor;
/**
* What kind of module is it?? Also contains a Minecraft colorcode for coloring
* your ArrayList :3
*
* @author godshawk
*
*/
public enum EnumHackType {
PLAYER(ChatColor.AQUA), GUI(ChatColor.GREEN), WORLD(ChatColor.GOLD), VISION(ChatColor.YELLOW), COMBAT(
ChatColor.DARK_RED), AURA(ChatColor.RED);
private final String color;
EnumHackType(final String color) {
this.color = color;
}
public final String getColor() {
return color;
}
public final String getName() {
return name().substring(0, 1).toUpperCase().concat(name().substring(1).toLowerCase());
}
}
Finally, we need the class that manages all the modules. It'll look something like this:
Code:
package com.luna.inkaria.handlers.module;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import com.luna.inkaria.console.ModCommand;
import com.luna.inkaria.handlers.console.ConsoleManager;
import com.luna.inkaria.loggers.InkariaLogger;
import com.luna.inkaria.module.Module;
import com.luna.inkaria.module.classes.ModuleConsole;
import com.luna.inkaria.module.classes.ModuleKillAura;
import com.luna.lib.annotations.Experimental;
import com.luna.lib.annotations.TestClass;
import com.luna.lib.loggers.enums.EnumLogType;
import com.luna.lib.reflection.ClassEnumerator;
/**
* Handles modules.
*
* ClassEnumerator is not working when reobfuscated, so I got lazy
*
* @author godshawk
*
*/
public final class ModuleManager {
private volatile Set<Module> modules;
private static volatile ModuleManager instance;
public ModuleManager() {
modules = new LinkedHashSet<>();
// Load modules here. I use some complicated Reflection to do this; you can do it however you want.
InkariaLogger.getInstance().log(EnumLogType.SUCCESS,
"Loaded " + modules.size() + " modules!");
}
private final void addModule(final Module e) {
synchronized (modules) {
modules.add(e);
}
}
public final Module getModuleByClass(final Class module) {
synchronized (modules) {
for (final Module e : modules) {
if (e.getClass().equals(module)) {
return e;
}
}
}
return null;
}
public final Module getModuleByName(final String module) {
synchronized (modules) {
for (final Module e : modules) {
if (e.getName().equals(module)) {
return e;
}
}
}
return null;
}
public final Set<Module> getModules() {
synchronized (modules) {
return Collections.unmodifiableSet(modules);
}
}
/**
* Returns the singleton instance of this
*
* @return
*/
public static final ModuleManager getInstance() {
if (instance == null) {
instance = new ModuleManager();
}
return instance;
}
}
First, go back to your main class; we need to add some stuff!
Code:
package com.luna.inkaria.core;
public final class Inkaria {
// Singleton instance
private static volatile Inkaria instance;
private Inkaria() {
// Loading...
// Loads the modules
ModuleManager.getInstance();
// Done loading!
}
// Returns the singleton instance of this class
public static Inkaria getInstance() {
if(instance == null) {
instance = new Inkaria();
}
return instance;
}
}
Code:
Inkaria.getInstance();
Skip down to runGameLoop(), the part that looks like this:
Code:
for (int var3 = 0; var3 < timer.elapsedTicks; ++var3) {
runTick();
}
You need to do keybinds now, so skip down to the part that looks like this:
Code:
if (Keyboard.getEventKeyState()) {
if (Keyboard.getEventKey() == 87) {
toggleFullscreen();
} else {
if (currentScreen != null) {
currentScreen.handleKeyboardInput();
} else {
Code:
EventManager.getInstance().fire(new EventKey(this, Keyboard.getEventKey()));
Code:
package com.luna.inkaria.events;
import com.luna.lib.event.EventBase;
/**
* Event for key presses
*
* @author godshawk
*
*/
public class EventKey extends EventBase {
private final int key;
public EventKey(final Object source, final int key) {
super(source);
this.key = key;
}
public final int getKey() {
return key;
}
}
Code:
package com.luna.inkaria.util.module;
import com.luna.inkaria.events.EventKey;
import com.luna.inkaria.handlers.module.ModuleManager;
import com.luna.inkaria.module.Module;
import com.luna.lib.annotations.EventListener;
import com.luna.lib.handlers.event.EventManager;
/**
* Checks for key presses, toggles the Module with the corresponding key.
*
* @author godshawk
*
*/
public class KeyboardHandler {
private static volatile KeyboardHandler instance;
public KeyboardHandler() {
EventManager.getInstance().addListener(this);
}
@EventListener(event = EventKey.class)
public void handleKeys(final EventKey f) {
final int key = f.getKey();
// InkariaLogger.getInstance().log("Key pressed: " + key);
for (final Module e : ModuleManager.getInstance().getModules()) {
if (key == e.getKey()) {
// InkariaLogger.getInstance().log("Module found: " +
// e.getName());
e.toggle();
}
}
}
public static KeyboardHandler getInstance() {
if (instance == null) {
instance = new KeyboardHandler();
}
return instance;
}
}
Finally, you need to add your Render3D event. EventRender3D looks exactly like your EventTick does, in that it just extends EventBase. You can call this where you like, but personally, I like calling it right at the beginning of EntityRenderer#renderHand().
Once you've finished all of this, you should have a (maybe) working client base! If you have questions, comments, concerns, or etc., please leave a comment below!
Also, here's an example module:
Code:
package com.luna.inkaria.module.classes;
import net.minecraft.src.Potion;
import net.minecraft.src.PotionEffect;
import org.lwjgl.input.Keyboard;
import com.luna.inkaria.events.EventTick;
import com.luna.inkaria.module.Module;
import com.luna.inkaria.module.enums.EnumHackType;
import com.luna.lib.annotations.EventListener;
import com.luna.lib.event.enums.EnumEventPriority;
/**
* Fullbright
*
* @author godshawk
*
*/
public class ModuleFullbright extends Module {
public ModuleFullbright() {
super("Fullbright", "Allows you to see in the dark", Keyboard.KEY_F, EnumHackType.WORLD);
registerDefaultCommand();
incompat(ModuleFlashlight.class);
}
@Override
@EventListener(event = EventTick.class, priority = EnumEventPriority.HIGH)
public void tick() {
getPlayer().removePotionEffect(Potion.nightVision.getId());
getPlayer().addPotionEffect(
new PotionEffect(Potion.nightVision.getId(), 99999999, 255, true));
}
@Override
public void render() {
// To change body of implemented methods use File | Settings | File
// Templates.
}
@Override
public void onDisable() {
getPlayer().removePotionEffect(Potion.nightVision.getId());
}
}
