Skip to content

Commit

Permalink
Experimental | Optimize & Use CommonItemResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
TheFloodDragon committed Aug 15, 2024
1 parent 76298d7 commit 50c0372
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package cn.fd.ratziel.core.serialization

import kotlinx.serialization.json.*
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import java.util.function.Function

/**
Expand Down Expand Up @@ -40,16 +43,12 @@ object JsonHandler {
}

/**
* 从给定 [JsonElement] 中寻找 [JsonPrimitive]
* 并通过 [action] 的操作后, 用返回的 [JsonElement] 替换掉原来的 [JsonPrimitive]
* 映射 [JsonPrimitive]
*/
fun handlePrimitives(element: JsonElement, action: Function<JsonPrimitive, JsonElement>): JsonElement =
when (element) {
is JsonPrimitive -> action.apply(element)
is JsonArray -> JsonArray(element.map { handlePrimitives(it, action) })
is JsonObject -> buildJsonObject {
element.forEach { put(it.key, handlePrimitives(it.value, action)) }
}
}
fun mapPrimitives(element: JsonElement, action: Function<JsonPrimitive, JsonElement>): JsonElement = when (element) {
is JsonPrimitive -> action.apply(element)
is JsonArray -> JsonArray(element.map { mapPrimitives(it, action) })
is JsonObject -> JsonObject(element.mapValues { mapPrimitives(it.value, action) })
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ inline fun JsonObject.handle(action: MutableJsonObject.(JsonObject) -> Unit): Js
inline fun JsonElement.toBasic(): Any = JsonHandler.toBasic(this)

/**
* 处理[JsonPrimitive]
* @see [JsonHandler.handlePrimitives]
* 映射 [JsonPrimitive]
* @see [JsonHandler.mapPrimitives]
*/
inline fun JsonElement.handlePrimitives(action: Function<JsonPrimitive, JsonElement>): JsonElement = JsonHandler.handlePrimitives(this, action)
inline fun JsonElement.mapPrimitives(action: Function<JsonPrimitive, JsonElement>): JsonElement = JsonHandler.mapPrimitives(this, action)

/**
* 合并目标
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,27 @@ open class MutableJsonObject(
* [MutableJsonObject] 存储的不可变 [JsonObject] 实例
* 其 [JsonObject.content] 应该与 [MutableJsonObject.content] 是同一个对象 (内存地址相同)
*/
protected open val immutable: JsonObject = JsonObject(content)
protected open val delegate: JsonObject = JsonObject(content)

/**
* 转化为不可变的 [JsonObject]
*/
open fun asImmutable() = immutable
open fun asImmutable() = delegate

/**
* @see [JsonObject.equals]
*/
override fun equals(other: Any?) = immutable == other
override fun equals(other: Any?) = delegate == other

/**
* @see [JsonObject.hashCode]
*/
override fun hashCode() = immutable.hashCode()
override fun hashCode() = delegate.hashCode()

/**
* @see [JsonObject.toString]
*/
override fun toString() = immutable.toString()
override fun toString() = delegate.toString()

/**
* [MutableJsonObject] 的序列化器
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cn.fd.ratziel.function

import java.util.concurrent.CopyOnWriteArraySet
import java.util.concurrent.CopyOnWriteArrayList

/**
* SimpleArgumentContext
Expand All @@ -9,21 +9,19 @@ import java.util.concurrent.CopyOnWriteArraySet
* @since 2024/6/28 16:19
*/
open class SimpleArgumentContext(
val collection: MutableCollection<Any>
) : ArgumentContext, MutableCollection<Any> by collection {
val list: MutableList<Any>
) : ArgumentContext, MutableList<Any> by list {

constructor(vararg values: Any) : this(CopyOnWriteArraySet<Any>().apply { values.forEach { add(it) } })
constructor(vararg values: Any) : this(CopyOnWriteArrayList<Any>().apply { addAll(values) })

override fun <T : Any> popOrNull(type: Class<T>): T? {
return uncheck(collection.find { type.isAssignableFrom(it::class.java) })
return uncheck(list.find { type.isAssignableFrom(it::class.java) })
}

override fun <T : Any> popAll(type: Class<T>): Iterable<T> {
return uncheck(collection.filter { type.isAssignableFrom(it::class.java) })
return uncheck(list.filter { type.isAssignableFrom(it::class.java) })
}

override fun args(): Collection<Any> {
return collection
}
override fun args(): Collection<Any> = list

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import cn.fd.ratziel.module.item.impl.builder.DefaultItemGenerator
import cn.fd.ratziel.module.item.nms.RefItemStack
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import taboolib.common.platform.event.SubscribeEvent
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

/**
Expand All @@ -26,14 +28,14 @@ object ItemElement : ElementHandler {
/**
* 构建物品用到的线程池
*/
val executor by lazy {
val executor: ExecutorService by lazy {
Executors.newFixedThreadPool(8)
}

/**
* 协程作用域
*/
val scope = CoroutineScope(Dispatchers.Default)
val buildScope = CoroutineScope(Dispatchers.Default)

init {
// 注册默认的东西
Expand All @@ -59,6 +61,8 @@ object ItemElement : ElementHandler {

@SubscribeEvent
fun onLoadStart(event: WorkspaceLoadEvent.Start) {
// 清除协程任务
buildScope.cancel()
// 清除注册的物品
ItemManager.registry.clear()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import cn.fd.ratziel.module.item.api.registry.ComponentRegistry
import cn.fd.ratziel.module.item.api.registry.ResolverRegistry
import cn.fd.ratziel.module.item.api.registry.SerializerRegistry
import cn.fd.ratziel.module.item.impl.builder.CommonItemResolver
import cn.fd.ratziel.module.item.impl.builder.DefaultItemSerializer
import cn.fd.ratziel.module.item.impl.builder.CommonItemSerializer
import cn.fd.ratziel.module.item.impl.component.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
Expand All @@ -28,7 +28,7 @@ object ItemRegistry {
*/
internal fun registerDefault() {
// 注册默认序列化器
Serializer.register(DefaultItemSerializer)
Serializer.register(CommonItemSerializer)
// 注册默认转换器
Component.register(ItemDisplay::class.java, ItemDisplay)
Component.register(ItemDurability::class.java, ItemDurability)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,41 @@
package cn.fd.ratziel.module.item.impl.builder

import cn.fd.ratziel.core.serialization.MutableJsonObject
import cn.fd.ratziel.core.serialization.JsonHandler
import cn.fd.ratziel.function.ArgumentContext
import cn.fd.ratziel.module.item.api.builder.ItemResolver
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.JsonElement
import java.util.concurrent.ConcurrentHashMap
import kotlinx.serialization.json.JsonObject

/**
* CommonItemResolver
*
* @author TheFloodDragon
* @since 2024/8/13 10:54
*/
class CommonItemResolver(
val element: JsonElement
) : ItemResolver {
object CommonItemResolver : ItemResolver {

/**
* 访问的节点, 通过 [CommonItemSerializer] 获取
* [SectionItemResolver] 应该访问的节点
*/
val visibleNode: Array<String> get() = CommonItemSerializer.usedNodes

/**
* 构建器 (支持多线程和异步)
*/
val builder: MutableJsonObject = newMap()
val visitNodes: Array<String> get() = CommonItemSerializer.usedNodes

/**
* 解析元素
*
* @return 解析完后, 返回值只包含 [visibleNode] 内的节点, 因此 [CommonItemSerializer] 需要作为最后一个解析
* @return 解析完后, 返回值只包含 [visitNodes] 内的节点, 因此 [CommonItemResolver] 需要作为最后一个解析
*/
override fun resolve(element: JsonElement, context: ArgumentContext): JsonElement = runBlocking {

TODO("Not yet implemented")
override fun resolve(element: JsonElement, context: ArgumentContext): JsonElement {
if (element !is JsonObject) return resolveBySection(element, context)
// 过滤节点
val builder: MutableMap<String, JsonElement> = HashMap()
for ((node, value) in element) {
if (visitNodes.contains(node)) builder[node] = resolveBySection(value, context)
}
return JsonObject(builder)
}

/**
* 创建一个可变的 [MutableJsonObject]
* 同时保证线程安全, 以支持 [resolve] 的操作
*/
private fun newMap() = MutableJsonObject(ConcurrentHashMap())
fun resolveBySection(element: JsonElement, context: ArgumentContext): JsonElement {
return JsonHandler.mapPrimitives(element) { SectionItemResolver.resolve(it, context) }
}

}
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
@file:OptIn(ExperimentalCoroutinesApi::class)

package cn.fd.ratziel.module.item.impl.builder

import cn.fd.ratziel.core.serialization.*
import cn.fd.ratziel.core.serialization.serializers.UUIDSerializer
import cn.fd.ratziel.core.serialization.elementAlias
import cn.fd.ratziel.core.serialization.getBy
import cn.fd.ratziel.core.serialization.getElementNames
import cn.fd.ratziel.core.serialization.handle
import cn.fd.ratziel.module.item.ItemElement
import cn.fd.ratziel.module.item.api.ItemMaterial
import cn.fd.ratziel.module.item.api.builder.ItemKSerializer
import cn.fd.ratziel.module.item.impl.builder.DefaultItemSerializer.json
import cn.fd.ratziel.module.item.impl.component.*
import cn.fd.ratziel.module.item.impl.component.serializers.*
import cn.fd.ratziel.module.nbt.NBTData
import cn.fd.ratziel.module.nbt.NBTSerializer
import kotlinx.serialization.DeserializationStrategy
import cn.fd.ratziel.module.item.impl.component.serializers.ItemMaterialSerializer
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
import kotlinx.coroutines.future.asCompletableFuture
import kotlinx.serialization.json.*
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.plus
import org.bukkit.attribute.Attribute
import org.bukkit.attribute.AttributeModifier
import org.bukkit.enchantments.Enchantment
import java.util.*
import java.util.concurrent.CompletableFuture

/**
* CommonItemSerializer
Expand All @@ -27,21 +25,6 @@ import java.util.concurrent.CompletableFuture
*/
object CommonItemSerializer : ItemKSerializer<ItemMetadata> {

val json = Json(baseJson) {
serializersModule += SerializersModule {
// Basic Serializers
contextual(UUID::class, UUIDSerializer)
// Common Serializers
contextual(NBTData::class, NBTSerializer)
contextual(ItemMaterial::class, ItemMaterialSerializer)
// Bukkit Serializers
contextual(Enchantment::class, EnchantmentSerializer)
contextual(HideFlag::class, HideFlagSerializer)
contextual(Attribute::class, AttributeSerializer)
contextual(AttributeModifier::class, AttributeModifierSerializer)
}
}

/**
* 使用到的节点
*/
Expand All @@ -66,20 +49,19 @@ object CommonItemSerializer : ItemKSerializer<ItemMetadata> {
override fun deserialize(element: JsonElement): ItemMetadata {
// 结构化解析
if (isStructured(element)) return json.decodeFromJsonElement(ItemMetadata.serializer(), element)
// 异步方法
fun <T> asyncDecode(deserializer: DeserializationStrategy<T>, from: JsonElement = element) =
CompletableFuture.supplyAsync({
json.decodeFromJsonElement(deserializer, from)
}, ItemElement.executor).exceptionally { it.printStackTrace();null }
// 一般解析
val display = asyncDecode(ItemDisplay.serializer())
val durability = asyncDecode(ItemDurability.serializer())
val sundry = asyncDecode(ItemSundry.serializer())
val characteristic = asyncDecode(ItemCharacteristic.serializer())
val material = (element as? JsonObject)?.getBy(NODES_MATERIAL)
?.let { asyncDecode(ItemMaterialSerializer, it) }
?: CompletableFuture.completedFuture(ItemMaterial.EMPTY)
return ItemMetadata(material.get(), display.get(), durability.get(), sundry.get(), characteristic.get())
val deferred = ItemElement.buildScope.async {
// 一般解析
val display = async { json.decodeFromJsonElement(ItemDisplay.serializer(), element) }
val durability = async { json.decodeFromJsonElement(ItemDurability.serializer(), element) }
val sundry = async { json.decodeFromJsonElement(ItemSundry.serializer(), element) }
val characteristic = async { json.decodeFromJsonElement(ItemCharacteristic.serializer(), element) }
val material = async {
val name = (element as? JsonObject)?.getBy(NODES_MATERIAL)
if (name != null) json.decodeFromJsonElement(ItemMaterialSerializer, name) else ItemMaterial.EMPTY
}
ItemMetadata(material.await(), display.await(), durability.await(), sundry.await(), characteristic.await())
}
return deferred.asCompletableFuture().get()
}

/**
Expand All @@ -94,13 +76,13 @@ object CommonItemSerializer : ItemKSerializer<ItemMetadata> {
*/
const val NODE_STRUCTURED = "structured"

internal fun isStructured(element: JsonElement): Boolean = try {
private fun isStructured(element: JsonElement): Boolean = try {
element.jsonObject[NODE_STRUCTURED]!!.jsonPrimitive.boolean
} catch (_: Exception) {
false
}

internal fun forceStructured(element: JsonElement): JsonElement = try {
private fun forceStructured(element: JsonElement): JsonElement = try {
element.jsonObject.handle { put(NODE_STRUCTURED, JsonPrimitive(true)) }
} catch (_: Exception) {
element
Expand Down
Loading

0 comments on commit 50c0372

Please sign in to comment.