Skip to content

Instantly share code, notes, and snippets.

@Sxtanna
Forked from MiniDigger/StructureUtil.java
Last active December 27, 2016 09:01
Show Gist options
  • Save Sxtanna/131df31228e497e7cb17d96bb41019cc to your computer and use it in GitHub Desktop.
Save Sxtanna/131df31228e497e7cb17d96bb41019cc to your computer and use it in GitHub Desktop.
Small util to load and save structures, using nms and reflection
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.util.Vector;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* "Small" util for loading and saving structures
*
* <br>Currently tested with 1.10 and 1.11</br>
*/
@SuppressWarnings({"FieldCanBeLocal", "unchecked"})
public class StructureUtil {
private static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
private static final String SAVE_NAME = VERSION.startsWith("v1_11") ? "c" : "d";
private static Class block;
private static Class world;
private static Class blocks;
private static Class blockPos;
private static Class worldServer;
private static Class craftWorld;
private static Class minecraftKey;
private static Class minecraftServer;
private static Class enumBlockMirror;
private static Class enumBlockRotation;
private static Class definedStructure;
private static Class definedStructureInfo;
private static Class definedStructureManager;
private static Object structureVoid;
private static Method getStructure;
private static Method getStructureManager;
private static Method getHandle;
private static Method getMinecraftServer;
private static Method enumBlockMirrorValueOf;
private static Method enumBlockRotationValueOf;
private static Method setPos;
private static Method setAuthor;
private static Method save;
private static Method load;
private static Method loadInfo;
private static Method mirror;
private static Method rotation;
private static Method ignoreEntities;
private static Constructor blockPosConstruct;
private static Constructor minecraftKeyConstruct;
private static Constructor definedStructureInfoConstruct;
static {
try {
block = nmsClass("Block");
world = nmsClass("World");
blocks = nmsClass("Blocks");
blockPos = nmsClass("BlockPosition");
craftWorld = obcClass("CraftWorld");
worldServer = nmsClass("WorldServer");
minecraftKey = nmsClass("MinecraftKey");
minecraftServer = nmsClass("MinecraftServer");
enumBlockMirror = nmsClass("EnumBlockMirror");
enumBlockRotation = nmsClass("EnumBlockRotation");
definedStructure = nmsClass("DefinedStructure");
definedStructureInfo = nmsClass("DefinedStructureInfo");
definedStructureManager = nmsClass("DefinedStructureManager");
structureVoid = blocks.getField("gj").get(null);
save = forArgsOf(definedStructureManager, SAVE_NAME, minecraftServer, minecraftKey);
load = forArgsOf(definedStructure, "a", world, blockPos, definedStructureInfo);
loadInfo = forArgsOf(definedStructureManager, "b", minecraftServer, minecraftKey);
mirror = forArgsOf(definedStructureInfo, "a", enumBlockMirror);
rotation = forArgsOf(definedStructureInfo, "a", enumBlockRotation);
ignoreEntities = forArgsOf(definedStructureInfo, "a", boolean.class);
setPos = forArgsOf(definedStructure, "a", world, blockPos, blockPos, boolean.class, block);
setAuthor = forArgsOf(definedStructure, "a", String.class);
getHandle = forArgsOf(craftWorld, "getHandle");
getStructure = forArgsOf(definedStructureManager, "a", minecraftServer, minecraftKey);
getMinecraftServer = forArgsOf(worldServer, "getMinecraftServer");
getStructureManager = forArgsOf(worldServer, "y");
enumBlockMirrorValueOf = forArgsOf(enumBlockMirror, "valueOf", String.class);
enumBlockRotationValueOf = forArgsOf(enumBlockRotation, "valueOf", String.class);
blockPosConstruct = forArgs(blockPos, int.class, int.class, int.class);
minecraftKeyConstruct = forArgs(minecraftKey, String.class);
definedStructureInfoConstruct = forArgs(definedStructureInfo);
}
catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
System.out.println("Failed to initialize reflection fields");
e.printStackTrace();
}
}
/**
* Save a Structure
*
* @param start The starting Location
* @param offSet The Offset, represented as a Vector
* @param name The name of the Structure
* @param author The name of the Author
* @param includeEntities If entities should be included in the save
*
* @return True if saved Successfully
*/
public static boolean save(Location start, Vector offSet, String name, String author, boolean includeEntities) {
try {
Object startPos = newInstance(blockPosConstruct, start.getBlockX(), start.getBlockY(), start.getBlockZ());
Object sizePos = newInstance(blockPosConstruct, offSet.getBlockX(), offSet.getBlockY(), offSet.getBlockZ());
Object world = getHandle.invoke(craftWorld.cast(start.getWorld()));
Object server = getMinecraftServer.invoke(world);
Object minecraftKey = newInstance(minecraftKeyConstruct, name);
Object structureManager = getStructureManager.invoke(world);
Object structure = getStructure.invoke(structureManager, server, minecraftKey);
setPos.invoke(structure, world, startPos, sizePos, includeEntities, structureVoid);
setAuthor.invoke(structure, author);
return ((boolean) save.invoke(structureManager, server, minecraftKey));
}
catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
System.out.println("Failed to save Structure " + name + " by " + author);
e.printStackTrace();
}
return false;
}
/**
* Load a Structure
*
* @param where Where to load this Structure
* @param name The name of the Structure
* @param mirrorType How it should be Mirrored [FRONT_BACK, LEFT_RIGHT or NONE]
* @param rotateType How it should be rotated [CLOCKWISE_90, CLOCKWISE_180, COUNTERCLOCKWISE_90 or NONE]
* @param includeEntities If saved entities should be loaded
*
* @return True if it loaded Successfully
*/
public static boolean load(Location where, String name, String mirrorType, String rotateType, boolean includeEntities) {
try {
Object wherePos = newInstance(blockPosConstruct, where.getBlockX(), where.getBlockY(), where.getBlockZ());
Object world = getHandle.invoke(craftWorld.cast(where.getWorld()));
Object server = getMinecraftServer.invoke(world);
Object minecraftKey = newInstance(minecraftKeyConstruct, name);
Object structureManager = getStructureManager.invoke(world);
Object structure = loadInfo.invoke(structureManager, server, minecraftKey);
if (structure != null) {
Object info = newInstance(definedStructureInfoConstruct);
mirror.invoke(info, enumBlockMirrorValueOf.invoke(null, mirrorType));
rotation.invoke(info, enumBlockRotationValueOf.invoke(null, rotateType));
ignoreEntities.invoke(info, includeEntities);
load.invoke(structure, world, wherePos, info);
return true;
}
}
catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
System.out.println("Failed to load Structure " + name + " at " + where.toVector() + " with params [" + mirrorType + ", " + rotateType + ", " + includeEntities + "]");
e.printStackTrace();
}
return false;
}
/**
* Get a class by name from the net.minecraft.server Package
*
* @param name The name of the Class
*
* @return The Class
* @throws ClassNotFoundException If the Class wasn't found
*/
private static Class<?> nmsClass(String name) throws ClassNotFoundException {
return Class.forName("net.minecraft.server." + VERSION + "." + name);
}
/**
* Get a class by name from the org.bukkit.craftbukkit Package
*
* @param name The name of the Class
*
* @return The Class
* @throws ClassNotFoundException If the Class wasn't found
*/
private static Class<?> obcClass(String name) throws ClassNotFoundException {
return Class.forName("org.bukkit.craftbukkit." + VERSION + "." + name);
}
/**
* Convenience method for getting a Constructor of a Class
*
* @param clazz The Class
* @param parameterTypes The target constructor's parameters
*
* @return The target Constructor
* @throws NoSuchMethodException If the Constructor isn't found
*/
private static Constructor<?> forArgs(Class<?> clazz, Class<?>... parameterTypes) throws NoSuchMethodException {
return clazz.getConstructor(parameterTypes);
}
/**
* Convenience method for getting a Method of a Class
*
* @param clazz The Class
* @param name The name of the Method
* @param parameterTypes The target method's parameters
*
* @return The target Method
* @throws NoSuchMethodException If the Method isn't found
*/
private static Method forArgsOf(Class<?> clazz, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
return clazz.getMethod(name, parameterTypes);
}
/**
* Convenience method for getting an Instance of a Class
*
* @param constructor The Constructor to use
* @param initArgs The Constructor parameters
*
* @return The new Object instance
*/
private static Object newInstance(Constructor<?> constructor, Object... initArgs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
return constructor.newInstance(initArgs);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment