Skip to content

Commit

Permalink
Add support for Spigot 1.10-1.12
Browse files Browse the repository at this point in the history
Signed-off-by: Christopher White <[email protected]>
  • Loading branch information
cswhite2000 committed Aug 7, 2023
1 parent c9c4b3e commit 4ccc1d6
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 26 deletions.
30 changes: 17 additions & 13 deletions core/src/main/java/tc/oc/pgm/wool/WoolMatchModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.util.Vector;
import tc.oc.pgm.api.PGM;
import tc.oc.pgm.api.event.BlockTransformEvent;
Expand Down Expand Up @@ -205,19 +206,22 @@ public void placementCheck(final BlockTransformEvent event) {

@EventHandler
public void handleWoolCrafting(PrepareItemCraftEvent event) {
ItemStack result = event.getRecipe().getResult();
InventoryHolder holder = event.getInventory().getHolder();

if (holder instanceof Player) {
MatchPlayer playerHolder = this.match.getPlayer((Player) holder);

if (playerHolder != null && result != null && result.getType() == Material.WOOL) {
for (MonumentWool wool : this.wools.values()) {
if (wool.getDefinition().isObjectiveWool(result)) {
if (!wool.getDefinition().isCraftable()) {
playerHolder.sendWarning(
translatable("wool.craftingDisabled", wool.getComponentName()));
event.getInventory().setResult(null);
Recipe recipe = event.getRecipe();
if (recipe != null) {
ItemStack result = recipe.getResult();
InventoryHolder holder = event.getInventory().getHolder();

if (holder instanceof Player) {
MatchPlayer playerHolder = this.match.getPlayer((Player) holder);

if (playerHolder != null && result != null && result.getType() == Material.WOOL) {
for (MonumentWool wool : this.wools.values()) {
if (wool.getDefinition().isObjectiveWool(result)) {
if (!wool.getDefinition().isCraftable()) {
playerHolder.sendWarning(
translatable("wool.craftingDisabled", wool.getComponentName()));
event.getInventory().setResult(null);
}
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion util/src/main/java/tc/oc/pgm/util/bukkit/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import tc.oc.pgm.util.ClassLogger;
import tc.oc.pgm.util.nms.NMSHacksNoOp;
import tc.oc.pgm.util.nms.NMSHacksPlatform;
import tc.oc.pgm.util.nms.v1_10_12.NMSHacks1_10_12;
import tc.oc.pgm.util.nms.v1_8.NMSHacksSportPaper;
import tc.oc.pgm.util.nms.v1_9.NMSHacks1_9;
import tc.oc.pgm.util.reflect.ReflectionUtils;
Expand All @@ -26,7 +27,13 @@ public enum Platform {
ReflectionUtils.getClassFromName("tc.oc.pgm.util.nms.v1_8.NMSHacks1_8"),
false),
SPIGOT_1_9("Spigot", "1.9", NMSHacks1_9.class, true),
PAPER_1_9("Paper", "1.9", NMSHacks1_9.class, true);
PAPER_1_9("Paper", "1.9", NMSHacks1_9.class, true),
SPIGOT_1_10("Spigot", "1.10", NMSHacks1_10_12.class, true),
PAPER_1_10("Paper", "1.10", NMSHacks1_10_12.class, true),
SPIGOT_1_11("Spigot", "1.11", NMSHacks1_10_12.class, true),
PAPER_1_11("Paper", "1.11", NMSHacks1_10_12.class, true),
SPIGOT_1_12("Spigot", "1.12", NMSHacks1_10_12.class, true),
PAPER_1_12("Paper", "1.12", NMSHacks1_10_12.class, true);

private static ClassLogger logger = ClassLogger.get(Platform.class);;
public static Platform SERVER_PLATFORM = computeServerPlatform();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ static EnumSet<Attribute> findMissingAttributes() {
}
}

return EnumSet.copyOf(missingAttributes);
return missingAttributes.isEmpty()
? EnumSet.noneOf(Attribute.class)
: EnumSet.copyOf(missingAttributes);
}

static org.bukkit.attribute.Attribute convertAttribute(Attribute attribute) {
Expand Down
7 changes: 6 additions & 1 deletion util/src/main/java/tc/oc/pgm/util/nms/reflect/Refl.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ interface NBTTagString {
Object build(String string);

@Reflect.Method("a_")
@Reflect.Method("c_")
String getString(Object item);
};

Expand Down Expand Up @@ -157,9 +158,13 @@ interface Block {
Object getBlockData(Object self);

@Reflect.Method("q")
@Reflect.Method(value = "q", parameters = IBlockData.class)
Object getMaterial(Object self);
}

@Reflect.NMS("IBlockData")
interface IBlockData {}
interface IBlockData {
@Reflect.Method("getMaterial")
Object getMaterial(Object self);
}
}
43 changes: 43 additions & 0 deletions util/src/main/java/tc/oc/pgm/util/nms/reflect/Reflect.java
Original file line number Diff line number Diff line change
@@ -1,52 +1,95 @@
package tc.oc.pgm.util.nms.reflect;

import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Reflect {
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(NMS.List.class)
@interface NMS {
String value();

Class<?>[] parameters() default {};

@Retention(RetentionPolicy.RUNTIME)
@interface List {
NMS[] value();
}
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(CB.List.class)
@interface CB {
String value();

Class<?>[] parameters() default {};

@Retention(RetentionPolicy.RUNTIME)
@interface List {
CB[] value();
}
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(B.List.class)
@interface B {
String value();

Class<?>[] parameters() default {};

@Retention(RetentionPolicy.RUNTIME)
@interface List {
B[] value();
}
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(StaticMethod.List.class)
@interface StaticMethod {
String value();

Class<?>[] parameters() default {};

@Retention(RetentionPolicy.RUNTIME)
@interface List {
StaticMethod[] value();
}
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Method.List.class)
@interface Method {
String value();

Class<?>[] parameters() default {};

@Retention(RetentionPolicy.RUNTIME)
@interface List {
Method[] value();
}
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Field.List.class)
@interface Field {
String value();

@Retention(RetentionPolicy.RUNTIME)
@interface List {
Field[] value();
}
}

@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Constructor.List.class)
@interface Constructor {
Class<?>[] value() default {};

@Retention(RetentionPolicy.RUNTIME)
@interface List {
Constructor[] value();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl

@Nullable
private static Function<Object[], Object> processComponent(Method method, Object[] args) {
if (method.isAnnotationPresent(Reflect.NMS.class)) {
if (method.getDeclaredAnnotationsByType(Reflect.NMS.class).length > 0) {
return processNMSComponent(method, args);
} else if (method.isAnnotationPresent(Reflect.CB.class)) {
} else if (method.getDeclaredAnnotationsByType(Reflect.CB.class).length > 0) {
return processCBComponent(method, args);
} else if (method.isAnnotationPresent(Reflect.B.class)) {
} else if (method.getDeclaredAnnotationsByType(Reflect.B.class).length > 0) {
return processBukkitComponent(method, args);
}
throw new RuntimeException("Error processing Method: " + method);
Expand All @@ -58,13 +58,13 @@ private static Function<Object[], Object> processComponent(Method method, Object
@Nullable
private static Function<Object[], Object> processComponent(
Method method, Object[] args, Class<?> parentClass) {
if (method.isAnnotationPresent(Reflect.StaticMethod.class)) {
if (method.getDeclaredAnnotationsByType(Reflect.StaticMethod.class).length > 0) {
return processStaticMethod(method, parentClass);
} else if (method.isAnnotationPresent(Reflect.Method.class)) {
} else if (method.getDeclaredAnnotationsByType(Reflect.Method.class).length > 0) {
return processMethod(method, args, parentClass);
} else if (method.isAnnotationPresent(Reflect.Field.class)) {
} else if (method.getDeclaredAnnotationsByType(Reflect.Field.class).length > 0) {
return processField(method, args, parentClass);
} else if (method.isAnnotationPresent(Reflect.Constructor.class)) {
} else if (method.getDeclaredAnnotationsByType(Reflect.Constructor.class).length > 0) {
return processConstructor(method, parentClass);
}
throw new RuntimeException("Error processing method: " + method);
Expand All @@ -87,11 +87,11 @@ private static Function<Object[], Object> processStaticMethod(

private static Function<Object[], Object> processMethod(
Method method, Object[] args, Class<?> parentClass) {
for (Reflect.Method staticMethod : method.getDeclaredAnnotationsByType(Reflect.Method.class)) {
for (Reflect.Method reflectMethod : method.getDeclaredAnnotationsByType(Reflect.Method.class)) {
try {
Method reflectedMethod =
parentClass.getMethod(
staticMethod.value(), processParameters(staticMethod.parameters()));
reflectMethod.value(), processParameters(reflectMethod.parameters()));
return callMethod(args, reflectedMethod);
} catch (NoSuchMethodException ignored) {
}
Expand Down
155 changes: 155 additions & 0 deletions util/src/main/java/tc/oc/pgm/util/nms/v1_10_12/NMSHacks1_10_12.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package tc.oc.pgm.util.nms.v1_10_12;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executors;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.material.MaterialData;
import org.bukkit.plugin.Plugin;
import tc.oc.pgm.util.attribute.AttributeMap;
import tc.oc.pgm.util.attribute.AttributeModifier;
import tc.oc.pgm.util.nms.attribute.AttributeMapBukkit;
import tc.oc.pgm.util.nms.reflect.Refl;
import tc.oc.pgm.util.nms.reflect.ReflectionProxy;

public class NMSHacks1_10_12 extends NMSHacksProtocolLib1_10_12 {
static Refl refl = ReflectionProxy.getProxy(Refl.class);
static Refl.NBTTagString nbtTagString = ReflectionProxy.getProxy(Refl.NBTTagString.class);
static Refl.NBTTagList nbtTagList = ReflectionProxy.getProxy(Refl.NBTTagList.class);
static Refl.NBTTagCompound nbtTagCompound = ReflectionProxy.getProxy(Refl.NBTTagCompound.class);
static Refl.CraftMagicNumbers craftMagicNumbers =
ReflectionProxy.getProxy(Refl.CraftMagicNumbers.class);
static Refl.Block reflBlock = ReflectionProxy.getProxy(Refl.Block.class);
static Refl.IBlockData reflIBlockData = ReflectionProxy.getProxy(Refl.IBlockData.class);
static Refl.CraftItemStack craftItemStack = ReflectionProxy.getProxy(Refl.CraftItemStack.class);

@Override
public Set<Material> getMaterialCollection(ItemMeta itemMeta, String key) {
Map<String, Object> unhandledTags = refl.getUnhandledTags(itemMeta);
if (!unhandledTags.containsKey(key)) return EnumSet.noneOf(Material.class);
EnumSet<Material> materialSet = EnumSet.noneOf(Material.class);
Object canDestroyList = unhandledTags.get(key);

for (Object item : (List<Object>) nbtTagList.getListField(canDestroyList)) {
String blockString = nbtTagString.getString(item);
Object nmsBlock = reflBlock.getBlockByName(blockString);
int id = reflBlock.getId(nmsBlock);
Material material = Material.getMaterial(id);
materialSet.add(material);
}

return materialSet;
}

@Override
public void setMaterialCollection(
ItemMeta itemMeta, Collection<Material> materials, String collectionName) {
Map<String, Object> unhandledTags = refl.getUnhandledTags(itemMeta);
Object canDestroyList =
unhandledTags.containsKey(collectionName)
? unhandledTags.get(collectionName)
: nbtTagList.build();
for (Material material : materials) {
Object block = craftMagicNumbers.getBlock(material);

if (block != null) {
String blockString = block.toString(); // Format: Block{what we want}
blockString = blockString.substring(6, blockString.length() - 1);
Object nbtString = nbtTagString.build(blockString);
nbtTagList.add(canDestroyList, nbtString);
}
}
if (!nbtTagList.isEmpty(canDestroyList)) unhandledTags.put(collectionName, canDestroyList);
}

@Override
public boolean canMineBlock(MaterialData blockMaterial, ItemStack tool) {
if (!blockMaterial.getItemType().isBlock()) {
throw new IllegalArgumentException("Material '" + blockMaterial + "' is not a block");
}

Object nmsBlock = craftMagicNumbers.getBlock(blockMaterial.getItemType());
Object nmsTool = tool == null ? null : craftMagicNumbers.getItem(tool.getType());

Object iBlockData = reflBlock.getBlockData(nmsBlock);

boolean alwaysDestroyable = refl.isAlwaysDestroyable(reflIBlockData.getMaterial(nmsBlock));
boolean toolCanDestroy = nmsTool != null && refl.canDestroySpecialBlock(nmsTool, iBlockData);
return nmsBlock != null && (alwaysDestroyable || toolCanDestroy);
}

@Override
public AttributeMap buildAttributeMap(Player player) {
return new AttributeMapBukkit(player);
}

@Override
public void applyAttributeModifiers(
SetMultimap<String, AttributeModifier> attributeModifiers, ItemMeta meta) {
Object list = nbtTagList.build();
if (!attributeModifiers.isEmpty()) {
for (Map.Entry<String, AttributeModifier> entry : attributeModifiers.entries()) {
AttributeModifier modifier = entry.getValue();
Object tag = nbtTagCompound.build();
nbtTagCompound.setString(tag, "Name", modifier.getName());
nbtTagCompound.setDouble(tag, "Amount", modifier.getAmount());
nbtTagCompound.setInt(tag, "Operation", modifier.getOperation().ordinal());
nbtTagCompound.setLong(tag, "UUIDMost", modifier.getUniqueId().getMostSignificantBits());
nbtTagCompound.setLong(tag, "UUIDLeast", modifier.getUniqueId().getLeastSignificantBits());
nbtTagCompound.setString(tag, "AttributeName", entry.getKey());
nbtTagList.add(list, tag);
}

Map<String, Object> unhandledTags = refl.getUnhandledTags(meta);

unhandledTags.put("AttributeModifiers", list);
}
}

@Override
public SetMultimap<String, AttributeModifier> getAttributeModifiers(ItemMeta meta) {
Map<String, Object> unhandledTags = refl.getUnhandledTags(meta);
if (unhandledTags.containsKey("AttributeModifiers")) {
final SetMultimap<String, AttributeModifier> attributeModifiers = HashMultimap.create();
final Object modTags = unhandledTags.get("AttributeModifiers");
for (int i = 0; i < nbtTagList.size(modTags); i++) {
final Object modTag = nbtTagList.get(modTags, i);
attributeModifiers.put(
nbtTagCompound.getString(modTag, "AttributeName"),
new AttributeModifier(
new UUID(
nbtTagCompound.getLong(modTag, "UUIDMost"),
nbtTagCompound.getLong(modTag, "UUIDLeast")),
nbtTagCompound.getString(modTag, "Name"),
nbtTagCompound.getDouble(modTag, "Amount"),
AttributeModifier.Operation.fromOpcode(
nbtTagCompound.getInt(modTag, "Operation"))));
}
return attributeModifiers;
} else {
return HashMultimap.create();
}
}

@Override
public ItemStack craftItemCopy(ItemStack item) {
return craftItemStack.asCraftCopy(item);
}

@Override
public void postToMainThread(Plugin plugin, boolean priority, Runnable task) {
Server bukkitServer = plugin.getServer();
Object nmsServer = refl.getNMSServer(refl.getCraftServerHandle(bukkitServer));
refl.addCallableToMainThread(nmsServer, Executors.callable(task));
}
}
Loading

0 comments on commit 4ccc1d6

Please sign in to comment.