Skip to content

Commit 52d106b

Browse files
committed
Fixed bugs related to reflection in the AnvilMenu and NBTData.
1 parent a82e5f9 commit 52d106b

File tree

8 files changed

+99
-87
lines changed

8 files changed

+99
-87
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ publishing {
4949
create<MavenPublication>("main") {
5050
group = projectGroup
5151
version = projectVersion
52-
artifactId = "lirand-api"
52+
artifactId = "LirandAPI"
5353

5454
from(components["kotlin"])
5555
artifact(tasks["sourcesJar"])

src/main/kotlin/lirand/api/architecture/KotlinPlugin.kt

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,12 @@ import lirand.api.LirandAPI
55

66
abstract class KotlinPlugin : SuspendingJavaPlugin() {
77

8-
open suspend fun onPluginLoad() {}
9-
open suspend fun onPluginEnable() {}
10-
open suspend fun onPluginDisable() {}
11-
12-
final override suspend fun onLoadAsync() {
13-
onPluginLoad()
14-
}
15-
16-
final override suspend fun onEnableAsync() {
8+
override fun onEnable() {
179
try {
1810
LirandAPI.register(this)
1911
} catch (_: IllegalStateException) {}
2012

21-
onPluginEnable()
22-
}
23-
24-
final override suspend fun onDisableAsync() {
25-
onPluginDisable()
13+
super.onEnable()
2614
}
2715

2816
}

src/main/kotlin/lirand/api/controllers/MenuController.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package lirand.api.controllers
22

3-
import com.github.shynixn.mccoroutine.launchAsync
3+
import com.github.shynixn.mccoroutine.launch
4+
import kotlinx.coroutines.delay
45
import lirand.api.dsl.menu.dynamic.anvil.AnvilMenu
56
import lirand.api.extensions.inventory.get
67
import lirand.api.extensions.inventory.isNotEmpty
@@ -75,7 +76,8 @@ internal class MenuController(val plugin: Plugin) : Listener, Controller {
7576
val text = event.currentItem?.itemMeta?.displayName ?: ""
7677
interact = PlayerMenuComplete(interact, text)
7778

78-
plugin.launchAsync {
79+
plugin.launch {
80+
delay(1)
7981
(menu as AnvilMenu).eventHandler.complete(interact)
8082
}
8183
}
@@ -112,7 +114,7 @@ internal class MenuController(val plugin: Plugin) : Listener, Controller {
112114
}
113115
}
114116

115-
@EventHandler(ignoreCancelled = true)
117+
@EventHandler
116118
fun onPrepareEvent(event: PrepareAnvilEvent) {
117119
val inventory = event.inventory
118120
val menu = inventory.asMenu() as? AnvilMenu ?: return
@@ -124,7 +126,8 @@ internal class MenuController(val plugin: Plugin) : Listener, Controller {
124126

125127
val prepare = PlayerAnvilMenuPrepare(menu, player, inventory, event.result)
126128

127-
plugin.launchAsync {
129+
plugin.launch {
130+
delay(1)
128131
menu.eventHandler.prepare(prepare)
129132
}
130133
}

src/main/kotlin/lirand/api/dsl/menu/dynamic/anvil/AnvilMenuImplementation.kt

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,25 +41,24 @@ class AnvilMenuImplementation(
4141
companion object {
4242
private val anvilWrapper: VersionWrapper = VersionMatcher().match()
4343

44-
private var inventoryField: Field? = null
45-
private var bukkitOwnerField: Field? = null
44+
private lateinit var inventoryField: Field
45+
private lateinit var bukkitOwnerField: Field
4646

4747
private fun verifyObfuscatedFields(container: Any) {
48-
if (inventoryField != null) return
48+
if (::inventoryField.isInitialized) return
4949

5050
inventoryField = container::class.java.allFields
5151
.find {
5252
if (it.type.simpleName != "IInventory") return@find false
53-
val inventoryClass = it.get(container)::class.java
53+
it.isAccessible = true
54+
val inventoryClass = it.get(container)::class.java.superclass
5455

55-
return@find (inventoryClass.simpleName == "InventorySubcontainer").also {
56-
bukkitOwnerField = inventoryClass.getField("bukkitOwner").apply {
56+
return@find (inventoryClass.simpleName == "InventorySubcontainer").ifTrue {
57+
bukkitOwnerField = inventoryClass.getDeclaredField("bukkitOwner").apply {
5758
isAccessible = true
5859
}
5960
}
60-
}!!.apply {
61-
isAccessible = true
62-
}
61+
}!!
6362
}
6463

6564
}
@@ -170,17 +169,19 @@ class AnvilMenuImplementation(
170169
close(player, true)
171170

172171
try {
172+
anvilWrapper.handleInventoryCloseEvent(player)
173+
anvilWrapper.setActiveContainerDefault(player)
174+
173175
val preOpen = PlayerMenuPreOpen(this, player)
174176
eventHandler.preOpen(preOpen)
175177

176178
if (preOpen.canceled) return
177179

178180
val title = dynamicTitle(player)
179181

180-
currentContainer = (anvilWrapper.newContainerAnvil(player, title)).apply {
181-
val inventory = inventoryField?.get(this)
182-
bukkitOwnerField?.set(inventory, this@AnvilMenuImplementation)
183-
}
182+
currentContainer = anvilWrapper.newContainerAnvil(player, title)
183+
184+
bukkitOwnerField.set(inventoryField.get(currentContainer), this)
184185

185186
_viewers[player] = inventory
186187

@@ -196,6 +197,7 @@ class AnvilMenuImplementation(
196197

197198
anvilWrapper.sendPacketOpenWindow(player, containerId, title)
198199
anvilWrapper.setActiveContainer(player, currentContainer)
200+
anvilWrapper.setActiveContainerId(currentContainer, containerId)
199201
anvilWrapper.addActiveContainerSlotListener(currentContainer, player)
200202

201203
if (job == null && updateDelay > 0 && _viewers.isNotEmpty())

src/main/kotlin/lirand/api/extensions/inventory/Serializer.kt

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,20 @@ object Serializer {
2121
""".trimIndent()
2222
}
2323

24-
fun deserializeItem(itemNbt: String): ItemStack? {
25-
return try {
26-
val asJsonObject = jsonParser.parse(itemNbt).asJsonObject
24+
fun deserializeItem(itemNbt: String): ItemStack? = try {
25+
val asJsonObject = jsonParser.parse(itemNbt).asJsonObject
2726

28-
val id = asJsonObject.getAsJsonPrimitive("id").asString
29-
val amount = asJsonObject.getAsJsonPrimitive("Count").asInt
30-
val nbt = asJsonObject.getAsJsonPrimitive("tag").asString
27+
val id = asJsonObject.getAsJsonPrimitive("id").asString
28+
val amount = asJsonObject.getAsJsonPrimitive("Count").asInt
29+
val nbt = asJsonObject.getAsJsonPrimitive("tag").asString
3130

32-
ItemStack(
33-
Material.matchMaterial(id)!!,
34-
amount,
35-
NBTData.deserialize(nbt)
36-
)
37-
} catch (exception: Throwable) {
38-
null
39-
}
31+
ItemStack(
32+
Material.matchMaterial(id)!!,
33+
amount,
34+
NBTData.deserialize(nbt)
35+
)
36+
} catch (exception: Throwable) {
37+
null
4038
}
4139

4240
fun serialize(inventory: Inventory, title: String? = null): String {
@@ -62,33 +60,31 @@ object Serializer {
6260
owner: InventoryHolder,
6361
inventoryNbt: String,
6462
title: String? = null
65-
): Inventory? {
66-
return try {
67-
val jsonObject = jsonParser.parse(inventoryNbt).asJsonObject
63+
): Inventory? = try {
64+
val jsonObject = jsonParser.parse(inventoryNbt).asJsonObject
6865

69-
val type = InventoryType.valueOf(
70-
jsonObject.getAsJsonPrimitive("type").asString.uppercase()
71-
)
72-
val size = if (type == InventoryType.CHEST)
73-
jsonObject.getAsJsonPrimitive("size").asInt
74-
else -1
75-
val resultTitle = if (title == null && jsonObject.has("title"))
76-
jsonObject.getAsJsonPrimitive("title").asString
77-
else title
66+
val type = InventoryType.valueOf(
67+
jsonObject.getAsJsonPrimitive("type").asString.uppercase()
68+
)
69+
val size = if (type == InventoryType.CHEST)
70+
jsonObject.getAsJsonPrimitive("size").asInt
71+
else -1
72+
val resultTitle = if (title == null && jsonObject.has("title"))
73+
jsonObject.getAsJsonPrimitive("title").asString
74+
else title
7875

79-
val result = if (type == InventoryType.CHEST)
80-
Inventory(owner, size, resultTitle)
81-
else
82-
Inventory(owner, type, resultTitle)
76+
val result = if (type == InventoryType.CHEST)
77+
Inventory(owner, size, resultTitle)
78+
else
79+
Inventory(owner, type, resultTitle)
8380

84-
val items = jsonObject.getAsJsonObject("Items")
85-
result.apply {
86-
for ((slot, item) in items.entrySet()) {
87-
setItem(slot.toInt(), deserializeItem(item.toString()))
88-
}
81+
val items = jsonObject.getAsJsonObject("Items")
82+
result.apply {
83+
for ((slot, item) in items.entrySet()) {
84+
setItem(slot.toInt(), deserializeItem(item.toString()))
8985
}
90-
} catch (exception: Throwable) {
91-
null
9286
}
87+
} catch (exception: Throwable) {
88+
null
9389
}
9490
}

src/main/kotlin/lirand/api/nbt/NBTDataLoader.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,28 @@ private val asNMSCopyMethod =
5151
craftItemStackClass.getMethod("asNMSCopy", ItemStack::class.java)
5252

5353
private val getItemMetaMethod = craftItemStackClass.methods
54-
.find { it.name == "getItemMeta" && it.parameterTypes[0].name == "" }!!
54+
.find { it.name == "getItemMeta" && it.parameterTypes.let {
55+
it.size == 1 && it[0] == asNMSCopyMethod.returnType
56+
} }!!
5557

5658

5759
private val minecraftEntityClass = getHandleMethod.returnType
5860

5961
private val minecraftEntityLoadMethod = minecraftEntityClass.methods
60-
.find { it.name == "load" && it.parameterTypes[0].simpleName == "NBTTagCompound" }!!
62+
.find { it.name == "load" && it.parameterTypes.let {
63+
it.size == 1 && it[0].simpleName == "NBTTagCompound"
64+
} }!!
6165
private val minecraftEntitySaveMethod = minecraftEntityClass.methods
62-
.find { it.name == "save" && it.parameterTypes[0].simpleName == "NBTTagCompound" }!!
66+
.find { it.name == "save" && it.parameterTypes.let {
67+
it.size == 1 && it[0].simpleName == "NBTTagCompound"
68+
} }!!
6369

6470

6571
private val minecraftItemStackClass = asNMSCopyMethod.returnType
6672

6773
private val minecraftItemStackHasTagMethod = minecraftItemStackClass.getMethod("hasTag")
6874
private val minecraftItemStackGetTagMethod = minecraftItemStackClass.getMethod("getTag")
6975
private val minecraftItemStackSetTagMethod = minecraftItemStackClass.methods
70-
.find { it.name == "setTag" && it.parameterTypes[0].simpleName == "NBTTagCompound" }!!
76+
.find { it.name == "setTag" && it.parameterTypes.let {
77+
it.size == 1 && it[0].simpleName == "NBTTagCompound"
78+
} }!!

src/main/kotlin/lirand/api/nbt/NBTDataType.kt

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package lirand.api.nbt
22

33
import java.lang.reflect.Method
4+
import kotlin.reflect.KClass
45

56
interface NBTDataType<T> {
67

@@ -70,23 +71,27 @@ interface NBTDataType<T> {
7071
private val nbtCompoundSetMethod = NBTData.nbtCompoundClass.methods
7172
.find {
7273
it.name == "set" && it.parameterTypes.let {
73-
it[0] == String::class.java && it[1].simpleName == "NBTBase"
74+
it.size >= 2 && it[0] == String::class.java && it[1].simpleName == "NBTBase"
7475
}
7576
}!!
7677

77-
private val nbtCompoundSetByteMethod = getSetMethod<Byte>("setByte")
78-
private val nbtCompoundSetByteArrayMethod = getSetMethod<ByteArray>("setByteArray")
79-
private val nbtCompoundSetDoubleMethod = getSetMethod<Double>("setDouble")
80-
private val nbtCompoundSetFloatMethod = getSetMethod<Float>("setFloat")
81-
private val nbtCompoundSetIntMethod = getSetMethod<Int>("setInt")
82-
private val nbtCompoundSetIntArrayMethod = getSetMethod<IntArray>("setIntArray")
83-
private val nbtCompoundSetLongMethod = getSetMethod<Long>("setLong")
84-
private val nbtCompoundSetLongArrayMethod = getSetMethod<LongArray>("setLongArray")
85-
private val nbtCompoundSetShortMethod = getSetMethod<Short>("setShort")
86-
private val nbtCompoundSetStringMethod = getSetMethod<String>("setString")
87-
88-
private inline fun <reified T> getSetMethod(name: String): Method {
89-
return NBTData.nbtCompoundClass.getMethod(name, String::class.java, T::class.java)
78+
private val nbtCompoundSetByteMethod = getSetMethod(Byte::class)
79+
private val nbtCompoundSetByteArrayMethod = getSetMethod(ByteArray::class)
80+
private val nbtCompoundSetDoubleMethod = getSetMethod(Double::class)
81+
private val nbtCompoundSetFloatMethod = getSetMethod(Float::class)
82+
private val nbtCompoundSetIntMethod = getSetMethod(Int::class)
83+
private val nbtCompoundSetIntArrayMethod = getSetMethod(IntArray::class)
84+
private val nbtCompoundSetLongMethod = getSetMethod(Long::class)
85+
private val nbtCompoundSetLongArrayMethod = getSetMethod(LongArray::class)
86+
private val nbtCompoundSetShortMethod = getSetMethod(Short::class)
87+
private val nbtCompoundSetStringMethod = getSetMethod(String::class)
88+
89+
private fun getSetMethod(clazz: KClass<*>): Method {
90+
return NBTData.nbtCompoundClass.methods.find {
91+
it.returnType == Void.TYPE && it.parameterTypes.let {
92+
it.size == 2 && it[0] == String::class.java && it[1] == clazz.java
93+
}
94+
}!!
9095
}
9196

9297

src/main/kotlin/lirand/api/utilities/Reflection.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,14 @@ val Class<*>.allMethods: List<Method>
2222
addAll(declaredMethods)
2323
currentClass = currentClass.superclass
2424
}
25+
}
26+
27+
val Class<*>.superclasses: List<Class<*>>
28+
get() = buildList {
29+
var currentClass: Class<*>? = this@superclasses
30+
while (true) {
31+
val superClass = currentClass?.superclass ?: break
32+
add(superClass)
33+
currentClass = superClass
34+
}
2535
}

0 commit comments

Comments
 (0)