2013-08-27 22:09:06 +02:00
|
|
|
package com.comphenix.protocol.wrappers;
|
|
|
|
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
import java.lang.reflect.Modifier;
|
|
|
|
|
|
|
|
import javax.annotation.Nonnull;
|
|
|
|
|
|
|
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
|
|
|
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
|
|
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
|
|
|
import com.google.common.base.Preconditions;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents a wrapper for the internal IntHashMap in Minecraft.
|
|
|
|
* @author Kristian
|
2019-05-04 05:22:44 +02:00
|
|
|
* @deprecated IntHashMap no longer exists
|
2013-08-27 22:09:06 +02:00
|
|
|
*/
|
2023-04-15 23:09:15 +02:00
|
|
|
@Deprecated
|
2013-12-09 13:46:41 +01:00
|
|
|
public class WrappedIntHashMap extends AbstractWrapper {
|
2023-05-12 16:35:34 +02:00
|
|
|
private static Method PUT_METHOD;
|
|
|
|
private static Method GET_METHOD;
|
|
|
|
private static Method REMOVE_METHOD;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct an IntHashMap wrapper around an instance.
|
|
|
|
* @param handle - the NMS instance.
|
|
|
|
*/
|
|
|
|
private WrappedIntHashMap(Object handle) {
|
|
|
|
super(MinecraftReflection.getIntHashMapClass());
|
|
|
|
setHandle(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct a new IntHashMap.
|
|
|
|
* @return A new IntHashMap.
|
|
|
|
*/
|
|
|
|
public static WrappedIntHashMap newMap() {
|
|
|
|
try {
|
|
|
|
return new WrappedIntHashMap(MinecraftReflection.getIntHashMapClass().newInstance());
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new RuntimeException("Unable to construct IntHashMap.", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct a wrapper around a given NMS IntHashMap.
|
|
|
|
* @param handle - the NMS IntHashMap.
|
|
|
|
* @return The created wrapped.
|
|
|
|
* @throws IllegalArgumentException If the handle is not an IntHasMap.
|
|
|
|
*/
|
|
|
|
public static WrappedIntHashMap fromHandle(@Nonnull Object handle) {
|
|
|
|
return new WrappedIntHashMap(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Associates a specified key with the given value in the integer map.
|
|
|
|
* <p>
|
|
|
|
* If the key has already been associated with a value, then it will be replaced by the new value.
|
|
|
|
* @param key - the key to insert.
|
|
|
|
* @param value - the value to insert. Cannot be NULL.
|
|
|
|
* @throws RuntimeException If the reflection machinery failed.
|
|
|
|
*/
|
|
|
|
public void put(int key, Object value) {
|
|
|
|
Preconditions.checkNotNull(value, "value cannot be NULL.");
|
|
|
|
|
|
|
|
initializePutMethod();
|
|
|
|
putInternal(key, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invoked when a value must be inserted into the underlying map, regardless of preconditions.
|
|
|
|
* @param key - the key.
|
|
|
|
* @param value - the value to insert.
|
|
|
|
*/
|
|
|
|
private void putInternal(int key, Object value) {
|
|
|
|
invokeMethod(PUT_METHOD, key, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the value associated with a specific key, or NULL if not found.
|
|
|
|
* @param key - the integer key.
|
|
|
|
* @return The associated value, or NULL.
|
|
|
|
*/
|
|
|
|
public Object get(int key) {
|
|
|
|
initializeGetMethod();
|
|
|
|
return invokeMethod(GET_METHOD, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a mapping of a key to a value if it is present.
|
|
|
|
* @param key - the key of the mapping to remove.
|
|
|
|
* @return The object that was removed, or NULL if the key is not present.
|
|
|
|
*/
|
|
|
|
public Object remove(int key) {
|
|
|
|
initializeGetMethod();
|
|
|
|
|
|
|
|
if (REMOVE_METHOD == null)
|
|
|
|
return removeFallback(key);
|
|
|
|
return invokeMethod(REMOVE_METHOD, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a entry in the IntHashMap using a fallback method.
|
|
|
|
* @param key - the key of the mapping to remove.
|
|
|
|
* @return The removed element.
|
|
|
|
*/
|
|
|
|
private Object removeFallback(int key) {
|
|
|
|
Object old = get(key);
|
|
|
|
|
|
|
|
invokeMethod(PUT_METHOD, key, null);
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invoke a particular method on the current handle
|
|
|
|
* @param method - the current method.
|
|
|
|
* @param params - parameters.
|
|
|
|
* @return The return value, if any.
|
|
|
|
*/
|
|
|
|
private Object invokeMethod(Method method, Object... params) {
|
|
|
|
try {
|
|
|
|
return method.invoke(handle, params);
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
throw new RuntimeException("Illegal argument.", e);
|
|
|
|
} catch (IllegalAccessException e) {
|
|
|
|
throw new RuntimeException("Cannot access method.", e);
|
|
|
|
} catch (InvocationTargetException e) {
|
|
|
|
throw new RuntimeException("Unable to invoke " + method + " on " + handle, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void initializePutMethod() {
|
|
|
|
if (PUT_METHOD == null) {
|
|
|
|
// Fairly straight forward
|
|
|
|
PUT_METHOD = FuzzyReflection.fromClass(MinecraftReflection.getIntHashMapClass()).getMethod(
|
|
|
|
FuzzyMethodContract.newBuilder().
|
|
|
|
banModifier(Modifier.STATIC).
|
|
|
|
parameterCount(2).
|
|
|
|
parameterExactType(int.class).
|
|
|
|
parameterExactType(Object.class).
|
|
|
|
build());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void initializeGetMethod() {
|
|
|
|
if (GET_METHOD == null) {
|
|
|
|
WrappedIntHashMap temp = WrappedIntHashMap.newMap();
|
|
|
|
String expected = "hello";
|
|
|
|
|
|
|
|
// Determine which method to trust
|
|
|
|
for (Method method : FuzzyReflection.fromClass(MinecraftReflection.getIntHashMapClass()).
|
|
|
|
getMethodListByParameters(Object.class, new Class<?>[] { int.class })) {
|
|
|
|
|
|
|
|
// Initialize a value
|
|
|
|
temp.put(1, expected);
|
|
|
|
|
|
|
|
// Skip static methods
|
|
|
|
if (Modifier.isStatic(method.getModifiers()))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
try {
|
|
|
|
boolean first = expected.equals(method.invoke(temp.getHandle(), 1));
|
|
|
|
boolean second = expected.equals(method.invoke(temp.getHandle(), 1));
|
|
|
|
|
|
|
|
// See if we found the method we are looking for
|
|
|
|
if (first && !second) {
|
|
|
|
REMOVE_METHOD = method;
|
|
|
|
} else if (first && second) {
|
|
|
|
GET_METHOD = method;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
// Suppress
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GET_METHOD == null)
|
|
|
|
throw new IllegalStateException("Unable to find appropriate GET_METHOD for IntHashMap.");
|
|
|
|
}
|
|
|
|
}
|
2013-08-27 22:09:06 +02:00
|
|
|
}
|