From 9ceb5b1b454f7c95cd7b7a630aa160dd355d4d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9D=8F=E9=BB=91?= Date: Thu, 4 Jul 2019 18:06:33 +0800 Subject: [PATCH] =?UTF-8?q?Add=20=E5=BA=8F=E5=88=97=E5=8C=96=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=20@TSerializeCollection=E3=80=81@TSerializeMap?= =?UTF-8?q?=E3=80=81@TSerializeCustom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/serialize/DoNotSerialize.java | 2 + .../serialize/TSerializeCollection.java | 18 +++ .../common/serialize/TSerializeCustom.java | 18 +++ .../{container => }/TSerializeMap.java | 8 +- .../common/serialize/TSerializer.java | 137 ++++++++++++++++-- .../common/serialize/TSerializerElement.java | 1 - .../serialize/TSerializerElementGeneral.java | 22 ++- .../common/serialize/TSerializerExample.java | 45 ++---- .../container/TSerializeCollection.java | 24 --- .../common/util/SimpleReflection.java | 48 ++++++ .../inventory/builder/v2/ClickEvent.java | 8 +- .../inventory/builder/v2/ClickListener.java | 4 +- .../inventory/builder/v2/MenuBuilder.java | 12 ++ 13 files changed, 265 insertions(+), 82 deletions(-) create mode 100644 src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCollection.java create mode 100644 src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCustom.java rename src/main/scala/me/skymc/taboolib/common/serialize/{container => }/TSerializeMap.java (66%) delete mode 100644 src/main/scala/me/skymc/taboolib/common/serialize/container/TSerializeCollection.java diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/DoNotSerialize.java b/src/main/scala/me/skymc/taboolib/common/serialize/DoNotSerialize.java index cd72c13..f6cee54 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/DoNotSerialize.java +++ b/src/main/scala/me/skymc/taboolib/common/serialize/DoNotSerialize.java @@ -8,6 +8,8 @@ import java.lang.annotation.Target; /** * @Author sky * @Since 2018-10-05 12:11 + * + * 用于标注不需要进行序列化的内容 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCollection.java b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCollection.java new file mode 100644 index 0000000..0b418da --- /dev/null +++ b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCollection.java @@ -0,0 +1,18 @@ +package me.skymc.taboolib.common.serialize; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @Author sky + * @Since 2018-10-05 12:11 + * + * 用于标识 Collection 类型的字段 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface TSerializeCollection { + +} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCustom.java b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCustom.java new file mode 100644 index 0000000..9f85ef5 --- /dev/null +++ b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeCustom.java @@ -0,0 +1,18 @@ +package me.skymc.taboolib.common.serialize; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @Author sky + * @Since 2018-10-05 12:11 + * + * 用于标识 TSerializable 类型的字段 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface TSerializeCustom { + +} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/container/TSerializeMap.java b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeMap.java similarity index 66% rename from src/main/scala/me/skymc/taboolib/common/serialize/container/TSerializeMap.java rename to src/main/scala/me/skymc/taboolib/common/serialize/TSerializeMap.java index 520d33f..27fcd43 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/container/TSerializeMap.java +++ b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializeMap.java @@ -1,20 +1,18 @@ -package me.skymc.taboolib.common.serialize.container; +package me.skymc.taboolib.common.serialize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.HashMap; -import java.util.Map; /** * @Author sky * @Since 2018-10-05 12:11 + * + * 用于标识 Map 类型的字段 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TSerializeMap { - Class type() default HashMap.class; - } \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializer.java b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializer.java index aa9dfe2..7c7bcf3 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializer.java +++ b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializer.java @@ -1,7 +1,9 @@ package me.skymc.taboolib.common.serialize; import ch.njol.skript.classes.ConfigurationSerializer; +import com.google.common.collect.Maps; import com.google.gson.*; +import me.skymc.taboolib.common.util.SimpleReflection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.serialization.ConfigurationSerializable; @@ -19,27 +21,65 @@ import java.util.Optional; */ public class TSerializer { + private static Map generated = Maps.newHashMap(); + public static T read(String value, Class type) { return ConfigurationSerializer.deserializeCS(value, type); } public static TSerializable read(TSerializable serializable, String serializedString) { + SimpleReflection.checkAndSave(serializable.getClass()); try { JsonObject jsonObject = (JsonObject) new JsonParser().parse(serializedString); if (jsonObject.has("serializeObject")) { JsonObject serializeObject = jsonObject.getAsJsonObject("serializeObject"); for (Map.Entry jsonElementEntry : serializeObject.entrySet()) { try { - Field declaredField = serializable.getClass().getDeclaredField(jsonElementEntry.getKey()); - declaredField.setAccessible(true); + Field declaredField = SimpleReflection.getField(serializable.getClass(), jsonElementEntry.getKey()); if (declaredField.isAnnotationPresent(DoNotSerialize.class)) { continue; } - Optional serializer = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(declaredField.getType())).findFirst(); - if (serializer.isPresent()) { - declaredField.set(serializable, serializer.get().getSerializer().read(jsonElementEntry.getValue().getAsString())); - } else { - serializable.read(jsonElementEntry.getKey(), jsonElementEntry.getValue().getAsString()); + // Serializable + if (declaredField.isAnnotationPresent(TSerializeCustom.class) && TSerializable.class.isAssignableFrom(declaredField.getType())) { + declaredField.set(serializable, generateElement((Class) declaredField.getType()).read(jsonElementEntry.getValue().getAsString())); + } + // List + else if (declaredField.isAnnotationPresent(TSerializeCollection.class) && Collection.class.isAssignableFrom(declaredField.getType())) { + Class listType = SimpleReflection.getListType(declaredField); + if (listType == null) { + serializable.read(jsonElementEntry.getKey(), jsonElementEntry.getValue().getAsString()); + continue; + } + TSerializerElementGeneral serializer = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(listType)).findFirst().orElse(null); + if (serializer == null) { + serializable.read(jsonElementEntry.getKey(), jsonElementEntry.getValue().getAsString()); + } else { + readCollection((Collection) declaredField.get(serializable), jsonElementEntry.getValue().getAsString(), checkCustom(listType, serializer)); + } + } + // Map + else if (declaredField.isAnnotationPresent(TSerializeMap.class) && Map.class.isAssignableFrom(declaredField.getType())) { + Class[] mapType = SimpleReflection.getMapType(declaredField); + if (mapType == null) { + serializable.read(jsonElementEntry.getKey(), jsonElementEntry.getValue().getAsString()); + continue; + } + TSerializerElementGeneral serializerK = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(mapType[0])).findFirst().orElse(null); + TSerializerElementGeneral serializerV = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(mapType[1])).findFirst().orElse(null); + if (serializerK == null || serializerV == null) { + serializable.read(jsonElementEntry.getKey(), jsonElementEntry.getValue().getAsString()); + } else { + readMap((Map) declaredField.get(serializable), jsonElementEntry.getValue().getAsString(), checkCustom(mapType[0], serializerK), checkCustom(mapType[1], serializerV)); + } + } + // 未声明类型 + else { + TSerializerElementGeneral serializer = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(declaredField.getType())).findFirst().orElse(null); + if (serializer == null) { + serializable.read(jsonElementEntry.getKey(), jsonElementEntry.getValue().getAsString()); + } else { + declaredField.set(serializable, serializer.getSerializer().read(jsonElementEntry.getValue().getAsString())); + } } } catch (Throwable t) { t.printStackTrace(); @@ -57,21 +97,57 @@ public class TSerializer { } public static String write(TSerializable serializable) { + SimpleReflection.checkAndSave(serializable.getClass()); JsonObject jsonObject = new JsonObject(); JsonObject serializeObject = new JsonObject(); - for (Field declaredField : serializable.getClass().getDeclaredFields()) { + for (Field declaredField : SimpleReflection.getFields(serializable.getClass()).values()) { try { if (!declaredField.isAnnotationPresent(DoNotSerialize.class) && !Modifier.isStatic(declaredField.getModifiers())) { - declaredField.setAccessible(true); - Object o = declaredField.get(serializable); - if (o == null) { + Object fieldObject = declaredField.get(serializable); + if (fieldObject == null) { continue; } - Optional serializer = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(declaredField.getType())).findFirst(); - if (serializer.isPresent()) { - serializeObject.addProperty(declaredField.getName(), serializer.get().getSerializer().write(o)); - } else { - Optional.ofNullable(serializable.write(declaredField.getName(), o)).ifPresent(value -> serializeObject.addProperty(declaredField.getName(), value)); + // Serializable + if (declaredField.isAnnotationPresent(TSerializeCustom.class) && TSerializable.class.isAssignableFrom(declaredField.getType())) { + serializeObject.addProperty(declaredField.getName(), generateElement((Class) declaredField.getType()).write(fieldObject)); + } + // List + else if (declaredField.isAnnotationPresent(TSerializeCollection.class) && Collection.class.isAssignableFrom(declaredField.getType())) { + Class listType = SimpleReflection.getListType(declaredField); + if (listType == null) { + Optional.ofNullable(serializable.write(declaredField.getName(), fieldObject)).ifPresent(value -> serializeObject.addProperty(declaredField.getName(), value)); + continue; + } + TSerializerElementGeneral serializer = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(listType)).findFirst().orElse(null); + if (serializer == null) { + Optional.ofNullable(serializable.write(declaredField.getName(), fieldObject)).ifPresent(value -> serializeObject.addProperty(declaredField.getName(), value)); + } else { + serializeObject.addProperty(declaredField.getName(), writeCollection((Collection) fieldObject, checkCustom(listType, serializer))); + } + } + // Map + else if (declaredField.isAnnotationPresent(TSerializeMap.class) && Map.class.isAssignableFrom(declaredField.getType())) { + Class[] mapType = SimpleReflection.getMapType(declaredField); + if (mapType == null) { + Optional.ofNullable(serializable.write(declaredField.getName(), fieldObject)).ifPresent(value -> serializeObject.addProperty(declaredField.getName(), value)); + continue; + } + TSerializerElementGeneral serializerK = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(mapType[0])).findFirst().orElse(null); + TSerializerElementGeneral serializerV = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(mapType[1])).findFirst().orElse(null); + if (serializerK == null || serializerV == null) { + Optional.ofNullable(serializable.write(declaredField.getName(), fieldObject)).ifPresent(value -> serializeObject.addProperty(declaredField.getName(), value)); + } else { + serializeObject.addProperty(declaredField.getName(), writeMap((Map) fieldObject, checkCustom(mapType[0], serializerK), checkCustom(mapType[1], serializerV))); + } + } + // 未声明类型 + else { + TSerializerElementGeneral serializer = Arrays.stream(TSerializerElementGeneral.values()).filter(serializerElements -> serializerElements.getSerializer().matches(declaredField.getType())).findFirst().orElse(null); + if (serializer == null) { + Optional.ofNullable(serializable.write(declaredField.getName(), fieldObject)).ifPresent(value -> serializeObject.addProperty(declaredField.getName(), value)); + } else { + serializeObject.addProperty(declaredField.getName(), serializer.getSerializer().write(fieldObject)); + } } } } catch (Throwable t) { @@ -168,4 +244,33 @@ public class TSerializer { Object o = y.get("value"); return !c.isInstance(o) ? null : (T) o; } + + public static TSerializerElement generateElement(Class serializable) { + return generated.computeIfAbsent(serializable.getName(), n -> new TSerializerElement() { + + @Override + public Object read(String value) { + try { + return serializable.newInstance().read(value); + } catch (Throwable t) { + t.printStackTrace(); + } + return null; + } + + @Override + public String write(Object value) { + return ((TSerializable) value).write(); + } + + @Override + public boolean matches(Class objectClass) { + return true; + } + }); + } + + private static TSerializerElement checkCustom(Class type, TSerializerElementGeneral serializer) { + return serializer == TSerializerElementGeneral.CUSTOM ? generateElement(type) : serializer.getSerializer(); + } } diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElement.java b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElement.java index e660389..9ad5932 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElement.java +++ b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElement.java @@ -11,5 +11,4 @@ public interface TSerializerElement { String write(T value); boolean matches(Class objectClass); - } \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElementGeneral.java b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElementGeneral.java index cd6de92..1697dd1 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElementGeneral.java +++ b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerElementGeneral.java @@ -182,7 +182,7 @@ public enum TSerializerElementGeneral { @Override public boolean matches(Class objectClass) { - return ItemStack.class.equals(objectClass); + return ItemStack.class.isAssignableFrom(objectClass); } }), @@ -200,7 +200,25 @@ public enum TSerializerElementGeneral { @Override public boolean matches(Class objectClass) { - return Location.class.equals(objectClass); + return Location.class.isAssignableFrom(objectClass); + } + }), + + CUSTOM(new TSerializerElement() { + + @Override + public Object read(String value) { + return null; + } + + @Override + public String write(Object value) { + return null; + } + + @Override + public boolean matches(Class objectClass) { + return TSerializable.class.isAssignableFrom(objectClass); } }); diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerExample.java b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerExample.java index d80333b..504ad7d 100644 --- a/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerExample.java +++ b/src/main/scala/me/skymc/taboolib/common/serialize/TSerializerExample.java @@ -2,8 +2,9 @@ package me.skymc.taboolib.common.serialize; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import me.skymc.taboolib.string.ArrayUtils; -import java.util.Collection; import java.util.List; import java.util.Map; @@ -15,17 +16,19 @@ public class TSerializerExample { public static void main(String[] args) { // 创建对象 - SimpleData date = new SimpleData(); + SimpleData data = new SimpleData(); // 修改参数 - date.number = 100; + data.number = 9999; + data.list.addAll(ArrayUtils.asList(111D, 222D)); + data.map.putAll(ImmutableMap.of("a", "b", "c", "d")); // 序列化 - String value = date.writeBase64(); + String value = data.write(); // 打印 System.out.println(value); // 创建新的对象 SimpleData dataCopy = new SimpleData(); // 反序列化 - dataCopy.readBase64(value); + dataCopy.read(value); // 打印 System.out.println(dataCopy); } @@ -44,14 +47,13 @@ public class TSerializerExample { private int number = 100; /** - * 特殊类型需要进行手动序列化 - * 标注 @TSerializeCollection 或 @TSerializeMap 来进行自动序列化(未完成) + * 包含基本类型的容器需要通过标注来完成序列化 */ -// @TSerializeCollection - private List list = Lists.newArrayList(1.0, 2.0, 3.0); + @TSerializeCollection + private List list = Lists.newArrayList(); -// @TSerializeMap - private Map map = ImmutableMap.of("abc", "def"); + @TSerializeMap + private Map map = Maps.newHashMap(); /** * 跳过序列化 @@ -59,32 +61,13 @@ public class TSerializerExample { @DoNotSerialize private String ignoreSerialize = "aaa"; - /** - * 基本类型不会执行以下两个方法 - * 由 TSerializer 自动进行序列化和反序列化步骤 - */ - @Override - public void read(String fieldName, String value) { - if (fieldName.equals("list")) { - // List 类型可以直接通过 TSerializer 提供的预设方法进行反序列化 - TSerializer.readCollection(list, value, TSerializerElementGeneral.DOUBLE); - } - } - - @Override - public String write(String fieldName, Object value) { - if (fieldName.equals("list")) { - return TSerializer.writeCollection((Collection) value, TSerializerElementGeneral.DOUBLE); - } - return null; - } - @Override public String toString() { return "SimpleData{" + "text='" + text + '\'' + ", number=" + number + ", list=" + list + + ", map=" + map + ", ignoreSerialize='" + ignoreSerialize + '\'' + '}'; } diff --git a/src/main/scala/me/skymc/taboolib/common/serialize/container/TSerializeCollection.java b/src/main/scala/me/skymc/taboolib/common/serialize/container/TSerializeCollection.java deleted file mode 100644 index 8b3a3f2..0000000 --- a/src/main/scala/me/skymc/taboolib/common/serialize/container/TSerializeCollection.java +++ /dev/null @@ -1,24 +0,0 @@ -package me.skymc.taboolib.common.serialize.container; - -import me.skymc.taboolib.common.serialize.TSerializerElement; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.Collection; - -/** - * @Author sky - * @Since 2018-10-05 12:11 - */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface TSerializeCollection { - - Class type() default ArrayList.class; - - Class element() default TSerializerElement.class; - -} \ No newline at end of file diff --git a/src/main/scala/me/skymc/taboolib/common/util/SimpleReflection.java b/src/main/scala/me/skymc/taboolib/common/util/SimpleReflection.java index 54cd0d7..c499ada 100644 --- a/src/main/scala/me/skymc/taboolib/common/util/SimpleReflection.java +++ b/src/main/scala/me/skymc/taboolib/common/util/SimpleReflection.java @@ -3,6 +3,8 @@ package me.skymc.taboolib.common.util; import com.google.common.collect.Maps; import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.Map; @@ -14,6 +16,24 @@ public class SimpleReflection { private static Map> fieldCached = Maps.newHashMap(); + public static boolean isExists(Class nmsClass) { + return fieldCached.containsKey(nmsClass.getName()); + } + + public static Map getFields(Class nmsClass) { + return fieldCached.getOrDefault(nmsClass.getName(), Maps.newHashMap()); + } + + public static Field getField(Class nmsClass, String fieldName) { + return fieldCached.getOrDefault(nmsClass.getName(), Maps.newHashMap()).get(fieldName); + } + + public static void checkAndSave(Class nmsClass) { + if (!isExists(nmsClass)) { + saveField(nmsClass); + } + } + public static void saveField(Class nmsClass) { try { Arrays.stream(nmsClass.getDeclaredFields()).forEach(declaredField -> saveField(nmsClass, declaredField.getName())); @@ -82,4 +102,32 @@ public class SimpleReflection { return def; } + public static Class getListType(Field field) { + Type genericType = field.getGenericType(); + try { + if (ParameterizedType.class.isAssignableFrom(genericType.getClass())) { + for (Type actualTypeArgument : ((ParameterizedType) genericType).getActualTypeArguments()) { + return Class.forName(actualTypeArgument.getTypeName()); + } + } + } catch (Throwable t) { + t.printStackTrace(); + } + return null; + } + + public static Class[] getMapType(Field field) { + Class[] mapType = new Class[2]; + try { + Type genericType = field.getGenericType(); + if (ParameterizedType.class.isAssignableFrom(genericType.getClass())) { + for (Type actualTypeArgument : ((ParameterizedType) genericType).getActualTypeArguments()) { + mapType[mapType[0] == null ? 0 : 1] = Class.forName(actualTypeArgument.getTypeName()); + } + } + } catch (Throwable t) { + t.printStackTrace(); + } + return mapType[1] == null ? null : mapType ; + } } diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickEvent.java b/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickEvent.java index 8471b58..913797f 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickEvent.java +++ b/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickEvent.java @@ -14,10 +14,12 @@ public class ClickEvent { private ClickType clickType; private Event event; + private char slot; - public ClickEvent(ClickType clickType, Event event) { + public ClickEvent(ClickType clickType, Event event, char slot) { this.clickType = clickType; this.event = event; + this.slot = slot; } public InventoryClickEvent castClick() { @@ -28,6 +30,10 @@ public class ClickEvent { return (InventoryDragEvent) event; } + public char getSlot() { + return slot; + } + public ClickType getClickType() { return clickType; } diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener.java b/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener.java index 67e20f2..5cbb4b7 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener.java +++ b/src/main/scala/me/skymc/taboolib/inventory/builder/v2/ClickListener.java @@ -32,14 +32,14 @@ class ClickListener implements Listener { if (((MenuHolder) e.getInventory().getHolder()).getBuilder().isLockHand() && (e.getRawSlot() - e.getInventory().getSize() - 27 == e.getWhoClicked().getInventory().getHeldItemSlot() || (e.getClick() == org.bukkit.event.inventory.ClickType.NUMBER_KEY && e.getHotbarButton() == e.getWhoClicked().getInventory().getHeldItemSlot()))) { e.setCancelled(true); } - Optional.ofNullable(((MenuHolder) e.getInventory().getHolder()).getBuilder().getClickTask()).ifPresent(t -> t.run(new ClickEvent(ClickType.CLICK, e))); + Optional.ofNullable(((MenuHolder) e.getInventory().getHolder()).getBuilder().getClickTask()).ifPresent(t -> t.run(new ClickEvent(ClickType.CLICK, e, ((MenuHolder) e.getInventory().getHolder()).getBuilder().getSlot(e.getRawSlot())))); } } @EventHandler public void onDrag(InventoryDragEvent e) { if (e.getInventory().getHolder() instanceof MenuHolder) { - Optional.ofNullable(((MenuHolder) e.getInventory().getHolder()).getBuilder().getClickTask()).ifPresent(t -> t.run(new ClickEvent(ClickType.DRAG, e))); + Optional.ofNullable(((MenuHolder) e.getInventory().getHolder()).getBuilder().getClickTask()).ifPresent(t -> t.run(new ClickEvent(ClickType.DRAG, e, ' '))); } } diff --git a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuBuilder.java b/src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuBuilder.java index 0e98b75..835fa52 100644 --- a/src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuBuilder.java +++ b/src/main/scala/me/skymc/taboolib/inventory/builder/v2/MenuBuilder.java @@ -86,6 +86,18 @@ public class MenuBuilder { } return inventory; } + + public char getSlot(int slot) { + for (int i = 0; i < items.length && i < rows; i++) { + char[] line = items[i]; + for (int j = 0; j < line.length && j < 9; j++) { + if (i * 9 + j == slot) { + return line[j]; + } + } + } + return ' '; + } // ********************************* //