Import an event api and optimize rendermodule by minor amounts

This commit is contained in:
ThisIsALegitUsername 2023-02-01 23:32:06 +00:00
parent 757e8b96a2
commit fa13428a38
16 changed files with 674 additions and 26 deletions

View File

@ -1,3 +1,4 @@
{ {
"java.dependency.packagePresentation": "hierarchical" "java.dependency.packagePresentation": "hierarchical",
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable"
} }

View File

@ -0,0 +1,44 @@
/**
* This is an API used for handling events across your java based projects.
* It's meant to be simple to use without sacrificing performance and extensibility.
*
* Currently the API is in beta phase but it's stable and ready to be used.
*
* If you have any suggestion for improvements/fixes for shit,
* feel free to make a pull request on the bitbucket: https://bitbucket.org/DarkMagician6/eventapi/overview.
*
* For information on how to use the API take a look at the wiki:
* https://bitbucket.org/DarkMagician6/eventapi/wiki/Home
*
* @Todo Improve/update the wiki.
*/
package com.darkmagician6.eventapi;
/**
* Main class for the API.
* Contains various information about the API.
*
* @author DarkMagician6
* @since July 31, 2013
*/
public final class EventAPI {
/**
* No need to create an Object of this class as all Methods are static.
*/
private EventAPI() {
}
/**
* The current version of the API.
*/
public static final String VERSION = String.format("%s-%s", "0.7", "beta");
/**
* Array containing the authors of the API.
*/
public static final String[] AUTHORS = {
"DarkMagician6"
};
}

View File

@ -0,0 +1,349 @@
package com.darkmagician6.eventapi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import com.darkmagician6.eventapi.events.Event;
import com.darkmagician6.eventapi.events.EventStoppable;
import com.darkmagician6.eventapi.types.Priority;
/**
*
*
* @author DarkMagician6
* @since February 2, 2014
*/
public final class EventManager {
/**
* HashMap containing all the registered MethodData sorted on the event parameters of the methods.
*/
private static final Map<Class<? extends Event>, List<MethodData>> REGISTRY_MAP = new HashMap<Class<? extends Event>, List<MethodData>>();
/**
* All methods in this class are static so there would be no reason to create an object of the EventManager class.
*/
private EventManager() {
}
/**
* Registers all the methods marked with the EventTarget annotation in the class of the given Object.
*
* @param object
* Object that you want to register.
*/
public static void register(Object object) {
for (final Method method : object.getClass().getDeclaredMethods()) {
if (isMethodBad(method)) {
continue;
}
register(method, object);
}
}
/**
* Registers the methods marked with the EventTarget annotation and that require
* the specified Event as the parameter in the class of the given Object.
*
* @param object
* Object that contains the Method you want to register.
* @param Parameter
* class for the marked method we are looking for.
*/
public static void register(Object object, Class<? extends Event> eventClass) {
for (final Method method : object.getClass().getDeclaredMethods()) {
if (isMethodBad(method, eventClass)) {
continue;
}
register(method, object);
}
}
/**
* Unregisters all the methods inside the Object that are marked with the EventTarget annotation.
*
* @param object
* Object of which you want to unregister all Methods.
*/
public static void unregister(Object object) {
for (final List<MethodData> dataList : REGISTRY_MAP.values()) {
for (final MethodData data : dataList) {
if (data.getSource().equals(object)) {
dataList.remove(data);
}
}
}
cleanMap(true);
}
/**
* Unregisters all the methods in the given Object that have the specified class as a parameter.
*
* @param object
* Object that implements the Listener interface.
* @param Parameter
* class for the method to remove.
*/
public static void unregister(Object object, Class<? extends Event> eventClass) {
if (REGISTRY_MAP.containsKey(eventClass)) {
for (final MethodData data : REGISTRY_MAP.get(eventClass)) {
if (data.getSource().equals(object)) {
REGISTRY_MAP.get(eventClass).remove(data);
}
}
cleanMap(true);
}
}
/**
* Registers a new MethodData to the HashMap.
* If the HashMap already contains the key of the Method's first argument it will add
* a new MethodData to key's matching list and sorts it based on Priority. @see com.darkmagician6.eventapi.types.Priority
* Otherwise it will put a new entry in the HashMap with a the first argument's class
* and a new CopyOnWriteArrayList containing the new MethodData.
*
* @param method
* Method to register to the HashMap.
* @param object
* Source object of the method.
*/
private static void register(Method method, Object object) {
Class<? extends Event> indexClass = (Class<? extends Event>) method.getParameterTypes()[0];
//New MethodData from the Method we are registering.
final MethodData data = new MethodData(object, method, method.getAnnotation(EventTarget.class).value());
//Set's the method to accessible so that we can also invoke it if it's protected or private.
if (!data.getTarget().isAccessible()) {
data.getTarget().setAccessible(true);
}
if (REGISTRY_MAP.containsKey(indexClass)) {
if (!REGISTRY_MAP.get(indexClass).contains(data)) {
REGISTRY_MAP.get(indexClass).add(data);
sortListValue(indexClass);
}
} else {
REGISTRY_MAP.put(indexClass, new CopyOnWriteArrayList<MethodData>() {
//Eclipse was bitching about a serialVersionUID.
private static final long serialVersionUID = 666L; {
add(data);
}
});
}
}
/**
* Removes an entry based on the key value in the map.
*
* @param indexClass
* They index key in the map of which the entry should be removed.
*/
public static void removeEntry(Class<? extends Event> indexClass) {
Iterator<Map.Entry<Class<? extends Event>, List<MethodData>>> mapIterator = REGISTRY_MAP.entrySet().iterator();
while (mapIterator.hasNext()) {
if (mapIterator.next().getKey().equals(indexClass)) {
mapIterator.remove();
break;
}
}
}
/**
* Cleans up the map entries.
* Uses an iterator to make sure that the entry is completely removed.
*
* @param onlyEmptyEntries
* If true only remove the entries with an empty list, otherwise remove all the entries.
*/
public static void cleanMap(boolean onlyEmptyEntries) {
Iterator<Map.Entry<Class<? extends Event>, List<MethodData>>> mapIterator = REGISTRY_MAP.entrySet().iterator();
while (mapIterator.hasNext()) {
if (!onlyEmptyEntries || mapIterator.next().getValue().isEmpty()) {
mapIterator.remove();
}
}
}
/**
* Sorts the List that matches the corresponding Event class based on priority value.
*
* @param indexClass
* The Event class index in the HashMap of the List to sort.
*/
private static void sortListValue(Class<? extends Event> indexClass) {
List<MethodData> sortedList = new CopyOnWriteArrayList<MethodData>();
for (final byte priority : Priority.VALUE_ARRAY) {
for (final MethodData data : REGISTRY_MAP.get(indexClass)) {
if (data.getPriority() == priority) {
sortedList.add(data);
}
}
}
//Overwriting the existing entry.
REGISTRY_MAP.put(indexClass, sortedList);
}
/**
* Checks if the method does not meet the requirements to be used to receive event calls from the Dispatcher.
* Performed checks: Checks if the parameter length is not 1 and if the EventTarget annotation is not present.
*
* @param method
* Method to check.
*
* @return True if the method should not be used for receiving event calls from the Dispatcher.
*
* @see com.darkmagician6.eventapi.EventTarget
*/
private static boolean isMethodBad(Method method) {
return method.getParameterTypes().length != 1 || !method.isAnnotationPresent(EventTarget.class);
}
/**
* Checks if the method does not meet the requirements to be used to receive event calls from the Dispatcher.
* Performed checks: Checks if the parameter class of the method is the same as the event we want to receive.
*
* @param method
* Method to check.
* @param Class
* of the Event we want to find a method for receiving it.
*
* @return True if the method should not be used for receiving event calls from the Dispatcher.
*
* @see com.darkmagician6.eventapi.EventTarget
*/
private static boolean isMethodBad(Method method, Class<? extends Event> eventClass) {
return isMethodBad(method) || !method.getParameterTypes()[0].equals(eventClass);
}
/**
* Call's an event and invokes the right methods that are listening to the event call.
* First get's the matching list from the registry map based on the class of the event.
* Then it checks if the list is not null. After that it will check if the event is an instance of
* EventStoppable and if so it will add an extra check when looping trough the data.
* If the Event was an instance of EventStoppable it will check every loop if the EventStoppable is stopped, and if
* it is it will break the loop, thus stopping the call.
* For every MethodData in the list it will invoke the Data's method with the Event as the argument.
* After that is all done it will return the Event.
*
* @param event
* Event to dispatch.
*
* @return Event in the state after dispatching it.
*/
public static final Event call(final Event event) {
List<MethodData> dataList = REGISTRY_MAP.get(event.getClass());
if (dataList != null) {
if (event instanceof EventStoppable) {
EventStoppable stoppable = (EventStoppable) event;
for (final MethodData data : dataList) {
invoke(data, event);
if (stoppable.isStopped()) {
break;
}
}
} else {
for (final MethodData data : dataList) {
invoke(data, event);
}
}
}
return event;
}
/**
* Invokes a MethodData when an Event call is made.
*
* @param data
* The data of which the targeted Method should be invoked.
* @param argument
* The called Event which should be used as an argument for the targeted Method.
*
* TODO: Error messages.
*/
private static void invoke(MethodData data, Event argument) {
try {
data.getTarget().invoke(data.getSource(), argument);
} catch (IllegalAccessException e) {
} catch (IllegalArgumentException e) {
} catch (InvocationTargetException e) {
}
}
/**
*
* @author DarkMagician6
* @since January 2, 2014
*/
private static final class MethodData {
private final Object source;
private final Method target;
private final byte priority;
/**
* Sets the values of the data.
*
* @param source
* The source Object of the data. Used by the VM to
* determine to which object it should send the call to.
* @param target
* The targeted Method to which the Event should be send to.
* @param priority
* The priority of this Method. Used by the registry to sort
* the data on.
*/
public MethodData(Object source, Method target, byte priority) {
this.source = source;
this.target = target;
this.priority = priority;
}
/**
* Gets the source Object of the data.
*
* @return Source Object of the targeted Method.
*/
public Object getSource() {
return source;
}
/**
* Gets the targeted Method.
*
* @return The Method that is listening to certain Event calls.
*/
public Method getTarget() {
return target;
}
/**
* Gets the priority value of the targeted Method.
*
* @return The priority value of the targeted Method.
*/
public byte getPriority() {
return priority;
}
}
}

View File

@ -0,0 +1,21 @@
package com.darkmagician6.eventapi;
import com.darkmagician6.eventapi.types.Priority;
import java.lang.annotation.*;
/**
* Marks a method so that the EventManager knows that it should be registered.
* The priority of the method is also set with this.
*
* @author DarkMagician6
* @see com.darkmagician6.eventapi.types.Priority
* @since July 30, 2013
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventTarget {
byte value() default Priority.MEDIUM;
}

View File

@ -0,0 +1,26 @@
package com.darkmagician6.eventapi.events;
/**
* Simple interface which should be implemented in events that can be cancelled.
*
* @author DarkMagician6
* @since August 27, 2013
*/
public interface Cancellable {
/**
* Gets the current cancelled state of the event.
*
* @return True if the event is cancelled.
*/
boolean isCancelled();
/**
* Sets the cancelled state of the event.
*
* @param state
* Whether the event should be cancelled or not.
*/
void setCancelled(boolean state);
}

View File

@ -0,0 +1,12 @@
package com.darkmagician6.eventapi.events;
/**
* The most basic form of an event.
* You have to implement this interface in order for the EventAPI to recognize the event.
*
* @author DarkMagician6
* @since July 30, 2013
*/
public interface Event {
}

View File

@ -0,0 +1,38 @@
package com.darkmagician6.eventapi.events;
/**
* The most basic form of an stoppable Event.
* Stoppable events are called seperate from other events and the calling of methods is stopped
* as soon as the EventStoppable is stopped.
*
* @author DarkMagician6
* @since 26-9-13
*/
public abstract class EventStoppable implements Event {
private boolean stopped;
/**
* No need for the constructor to be public.
*/
protected EventStoppable() {
}
/**
* Sets the stopped state to true.
*/
public void stop() {
stopped = true;
}
/**
* Checks the stopped boolean.
*
* @return
* True if the EventStoppable is stopped.
*/
public boolean isStopped() {
return stopped;
}
}

View File

@ -0,0 +1,24 @@
package com.darkmagician6.eventapi.events;
/**
* Simple interface that should be implemented in typed events.
* A typed event is an event that can be called on multiple places
* with the type defining where it was called.
* <p/>
* The type should be defined in the constructor when the new instance
* of the event is created.
*
* @author DarkMagician6
* @since August 27, 2013
*/
public interface Typed {
/**
* Gets the current type of the event.
*
* @return The type ID of the event.
*/
byte getType();
}

View File

@ -0,0 +1,35 @@
package com.darkmagician6.eventapi.events.callables;
import com.darkmagician6.eventapi.events.Cancellable;
import com.darkmagician6.eventapi.events.Event;
/**
* Abstract example implementation of the Cancellable interface.
*
* @author DarkMagician6
* @since August 27, 2013
*/
public abstract class EventCancellable implements Event, Cancellable {
private boolean cancelled;
protected EventCancellable() {
}
/**
* @see com.darkmagician6.eventapi.events.Cancellable.isCancelled
*/
@Override
public boolean isCancelled() {
return cancelled;
}
/**
* @see com.darkmagician6.eventapi.events.Cancellable.setCancelled
*/
@Override
public void setCancelled(boolean state) {
cancelled = state;
}
}

View File

@ -0,0 +1,34 @@
package com.darkmagician6.eventapi.events.callables;
import com.darkmagician6.eventapi.events.Event;
import com.darkmagician6.eventapi.events.Typed;
/**
* Abstract example implementation of the Typed interface.
*
* @author DarkMagician6
* @since August 27, 2013
*/
public abstract class EventTyped implements Event, Typed {
private final byte type;
/**
* Sets the type of the event when it's called.
*
* @param eventType
* The type ID of the event.
*/
protected EventTyped(byte eventType) {
type = eventType;
}
/**
* @see com.darkmagician6.eventapi.events.Typed.getType
*/
@Override
public byte getType() {
return type;
}
}

View File

@ -0,0 +1,21 @@
package com.darkmagician6.eventapi.types;
/**
* Types that can be used for typed events.
*
* @author DarkMagician6
* @since August 27, 2013
*/
public class EventType {
/**
* Used to define the type of a typed event.
*/
public static final byte
PRE = 0,
ON = 1,
POST = 2,
SEND = 3,
RECIEVE = 4;
}

View File

@ -0,0 +1,54 @@
package com.darkmagician6.eventapi.types;
/**
* The priority for the dispatcher to determine what method should be invoked first.
* Ram was talking about the memory usage of the way I store the data so I decided
* to just use bytes for the priority because they take up only 8 bits of memory
* per value compared to the 32 bits per value of an enum (Same as an integer).
*
* @author DarkMagician6
* @since August 3, 2013
*/
public final class Priority {
public static final byte
/**
* Highest priority, called first.
*/
HIGHEST = 0,
/**
* High priority, called after the highest priority.
*/
HIGH = 1,
/**
* Medium priority, called after the high priority.
*/
MEDIUM = 2,
/**
* Low priority, called after the medium priority.
*/
LOW = 3,
/**
* Lowest priority, called after all the other priorities.
*/
LOWEST = 4;
/**
* Array containing all the prioriy values.
*/
public static final byte[] VALUE_ARRAY;
/**
* Sets up the VALUE_ARRAY the first time anything in this class is called.
*/
static {
VALUE_ARRAY = new byte[]{
HIGHEST,
HIGH,
MEDIUM,
LOW,
LOWEST
};
}
}

View File

@ -14,5 +14,5 @@ public @interface RenderMod {
Category category(); Category category();
int x(); int x();
int y(); int y();
boolean hasSetting(); boolean hasSetting() default false;
} }

View File

@ -1,6 +1,7 @@
package dev.resent.module.base; package dev.resent.module.base;
import dev.resent.annotation.RenderMod; import dev.resent.annotation.RenderMod;
import dev.resent.util.render.RenderUtils;
import net.lax1dude.eaglercraft.v1_8.Mouse; import net.lax1dude.eaglercraft.v1_8.Mouse;
import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiScreen;
@ -70,22 +71,16 @@ public class RenderModule extends Mod {
boolean hovered = mouseX >= getX() && mouseY >= getY() && mouseX < getX() + getWidth() && mouseY < getY() + this.getHeight(); boolean hovered = mouseX >= getX() && mouseY >= getY() && mouseX < getX() + getWidth() && mouseY < getY() + this.getHeight();
Gui.drawRect(this.x, this.y, this.x + this.getWidth(), this.y + this.getHeight(), hovered ? 0x50FFFFFF : 0x40FFFFFF); Gui.drawRect(this.x, this.y, this.x + this.getWidth(), this.y + this.getHeight(), hovered ? 0x50FFFFFF : 0x40FFFFFF);
Gui.drawRect(this.x, this.y, this.x + this.getWidth(), this.y + 1, -1); RenderUtils.drawRectOutline(this.x, this.y, this.x+this.getWidth(), this.y+this.getHeight(), -1);
Gui.drawRect(this.x, this.y, this.x + 1, this.y + getHeight(), -1);
Gui.drawRect(this.x + this.getWidth() - 1, this.y, this.x + getWidth(), this.y + this.getHeight(), -1);
Gui.drawRect(this.x, this.y + this.getHeight() - 1, this.x + getWidth(), this.y + this.getHeight(), -1);
boolean mouseOverX = (mouseX >= this.getX() && mouseX <= this.getX() + this.getWidth()); boolean mouseOverX = (mouseX >= this.getX() && mouseX <= this.getX() + this.getWidth());
boolean mouseOverY = (mouseY >= this.getY() && mouseY <= this.getY() + this.getHeight()); boolean mouseOverY = (mouseY >= this.getY() && mouseY <= this.getY() + this.getHeight());
if (mouseOverX && mouseOverY) {
if (Mouse.isButtonDown(0)) { if (mouseOverX && mouseOverY && Mouse.isButtonDown(0) && !this.dragging) {
if (!this.dragging) {
this.lastX = x - mouseX; this.lastX = x - mouseX;
this.lastY = y - mouseY; this.lastY = y - mouseY;
this.dragging = true; this.dragging = true;
} }
}
}
} }

View File

@ -1,5 +1,6 @@
package dev.resent.module.impl.hud; package dev.resent.module.impl.hud;
import dev.resent.annotation.RenderMod;
import dev.resent.module.base.Category; import dev.resent.module.base.Category;
import dev.resent.module.base.RenderModule; import dev.resent.module.base.RenderModule;
import dev.resent.module.setting.BooleanSetting; import dev.resent.module.setting.BooleanSetting;
@ -8,14 +9,12 @@ import net.minecraft.client.gui.GuiIngame;
import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@RenderMod(name = "ArmorHud", category = Category.HUD, x = 15, y = 4, hasSetting = true)
public class ArmorHud extends RenderModule { public class ArmorHud extends RenderModule {
public ScaledResolution sr; public ScaledResolution sr;
public ArmorHud() { public ArmorHud() { addSetting(helm, chestp, leg, boot, item); }
super("ArmorHud", Category.HUD, 4, 4, true);
addSetting(helm, chestp, leg, boot, item);
}
public static BooleanSetting helm = new BooleanSetting("Helmet", "", true); public static BooleanSetting helm = new BooleanSetting("Helmet", "", true);
public static BooleanSetting chestp = new BooleanSetting("Chestplate", "", true); public static BooleanSetting chestp = new BooleanSetting("Chestplate", "", true);
@ -23,13 +22,8 @@ public class ArmorHud extends RenderModule {
public static BooleanSetting boot = new BooleanSetting("Boots", "", true); public static BooleanSetting boot = new BooleanSetting("Boots", "", true);
public static BooleanSetting item = new BooleanSetting("Item", "", true); public static BooleanSetting item = new BooleanSetting("Item", "", true);
public int getWidth() { public int getWidth() { return 20; }
return 20; public int getHeight() { return 96; }
}
public int getHeight() {
return 96;
}
@Override @Override
public void draw() { public void draw() {