diff --git a/src/main/kotlin/cf/wayzer/contentsTweaker/PatchHandler.kt b/src/main/kotlin/cf/wayzer/contentsTweaker/PatchHandler.kt index eb70a33..5142da4 100644 --- a/src/main/kotlin/cf/wayzer/contentsTweaker/PatchHandler.kt +++ b/src/main/kotlin/cf/wayzer/contentsTweaker/PatchHandler.kt @@ -63,16 +63,16 @@ object PatchHandler { return "Node(key='$key')" } - interface WithObj { - val obj: Any? - val type: Class<*>? + interface WithObj { + val obj: T + val type: Class<*> val elementType: Class<*>? get() = null val keyType: Class<*>? get() = null } //Node with obj, not Modifiable, use as simple node - class ObjNode(override val parent: Node, key: String, override val obj: Any, override val type: Class = obj.javaClass) : - Node(key), WithObj + class ObjNode(override val parent: Node, key: String, override val obj: T, override val type: Class = obj.javaClass) : + Node(key), WithObj interface Storable { val storeDepth: Int @@ -80,22 +80,11 @@ object PatchHandler { fun doRecover() } - interface Modifiable : WithObj, Storable { - // /** -// * 可直接修改[obj]对象.通过其他机制可保证还原 -// * true时: [doStore0]负责拷贝对象,并保存,由[recover]负责恢复 -// * false时: 由[Modifier]负责产生新对象并[setValue] -// * */ -// val mutableObj: Boolean get() = false - fun setValue(value: Any?) -// fun doStore() { -// if (mutableObj) error("mutable Modifiable need impl doStore0 to backup obj") -// } -// -// fun recover() { -// if (mutableObj) error("mutable Modifiable need impl recover to recover obj") -// setValue(obj) -// } + interface Modifiable : WithObj, Storable { + fun setValue(value: T) + + @Suppress("UNCHECKED_CAST") + fun setValueAny(value: Any?) = setValue(type.cast(value) as T) } fun interface Modifier { diff --git a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/BaseModifier.kt b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/BaseModifier.kt index c507eec..600aca4 100644 --- a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/BaseModifier.kt +++ b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/BaseModifier.kt @@ -8,11 +8,11 @@ import cf.wayzer.contentsTweaker.TypeRegistry object BaseModifier : PatchHandler.Resolver { override fun resolve(node: Node, child: String): Node? { if (child != "=") return null - if (node !is Node.Modifiable) error("${node.key} is not Modifiable, can't assign") + if (node !is Node.Modifiable<*>) error("${node.key} is not Modifiable, can't assign") return node.withModifier(child) { json -> val value = TypeRegistry.resolveType(json, type, elementType, keyType) beforeModify() - setValue(value) + setValueAny(value) } } } \ No newline at end of file diff --git a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/BlockConsumesResolver.kt b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/BlockConsumesResolver.kt index 152b9e7..4f5e034 100644 --- a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/BlockConsumesResolver.kt +++ b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/BlockConsumesResolver.kt @@ -11,55 +11,54 @@ import mindustry.world.consumers.* object BlockConsumesResolver : PatchHandler.Resolver, TypeRegistry.Resolver { override fun resolve(node: Node, child: String): Node? { - if (node is Node.Modifiable && node.obj is Array<*> && node.elementType == Consume::class.java) { - val block = ((node.parent as Node.WithObj).obj as? Block) ?: return null - fun modifier(body: Array.(JsonValue) -> Array) = node.withModifier(child) { - beforeModify() - PatchHandler.registerAfterHandler(node.key) { - block.apply { - consPower = consumers.filterIsInstance().firstOrNull() - optionalConsumers = consumers.filter { it.optional && !it.ignore() }.toTypedArray() - nonOptionalConsumers = consumers.filter { !it.optional && !it.ignore() }.toTypedArray() - updateConsumers = consumers.filter { it.update && !it.ignore() }.toTypedArray() - hasConsumers = consumers.isNotEmpty() - itemFilter.fill(false) - liquidFilter.fill(false) - consumers.forEach { it.apply(this) } - setBars() - } + if (node !is Node.Modifiable<*> || !Array::class.java.isAssignableFrom(node.type)) + return null + val block = ((node.parent as Node.WithObj<*>).obj as? Block) ?: return null + fun modifier(body: Array.(JsonValue) -> Array) = node.withModifier(child) { v -> + beforeModify() + PatchHandler.registerAfterHandler(key) { + block.apply { + consPower = consumers.filterIsInstance().firstOrNull() + optionalConsumers = consumers.filter { it.optional && !it.ignore() }.toTypedArray() + nonOptionalConsumers = consumers.filter { !it.optional && !it.ignore() }.toTypedArray() + updateConsumers = consumers.filter { it.update && !it.ignore() }.toTypedArray() + hasConsumers = consumers.isNotEmpty() + itemFilter.fill(false) + liquidFilter.fill(false) + consumers.forEach { it.apply(this) } + setBars() } - @Suppress("UNCHECKED_CAST") val obj = node.obj as Array - setValue(obj.body(it)) } - return when (child) { - "clearItems" -> modifier { filterNot { it is ConsumeItems || it is ConsumeItemFilter }.toTypedArray() } - "item" -> modifier { this + ConsumeItems(arrayOf(ItemStack(TypeRegistry.resolve(it), 1))) } - "items" -> modifier { this + TypeRegistry.resolve(it) } - "itemCharged" -> modifier { this + TypeRegistry.resolve(it) } - "itemFlammable" -> modifier { this + TypeRegistry.resolve(it) } - "itemRadioactive" -> modifier { this + TypeRegistry.resolve(it) } - "itemExplosive" -> modifier { this + TypeRegistry.resolve(it) } - "itemExplode" -> modifier { this + TypeRegistry.resolve(it) } - - "clearLiquids" -> modifier { filterNot { it is ConsumeLiquidBase || it is ConsumeLiquids }.toTypedArray() } - "liquid" -> modifier { this + TypeRegistry.resolve(it) } - "liquids" -> modifier { this + TypeRegistry.resolve(it) } - "liquidFlammable" -> modifier { this + TypeRegistry.resolve(it) } - "coolant" -> modifier { this + TypeRegistry.resolve(it) } + @Suppress("UNCHECKED_CAST") + setValueAny((obj as Array).body(v)) + } + return when (child) { + "clearItems" -> modifier { filterNot { it is ConsumeItems || it is ConsumeItemFilter }.toTypedArray() } + "item" -> modifier { this + ConsumeItems(arrayOf(ItemStack(TypeRegistry.resolve(it), 1))) } + "items" -> modifier { this + TypeRegistry.resolve(it) } + "itemCharged" -> modifier { this + TypeRegistry.resolve(it) } + "itemFlammable" -> modifier { this + TypeRegistry.resolve(it) } + "itemRadioactive" -> modifier { this + TypeRegistry.resolve(it) } + "itemExplosive" -> modifier { this + TypeRegistry.resolve(it) } + "itemExplode" -> modifier { this + TypeRegistry.resolve(it) } - "clearPower" -> modifier { filterNot { it is ConsumePower }.toTypedArray() } - "power" -> modifier { - this.filterNot { c -> c is ConsumePower }.toTypedArray() + TypeRegistry.resolve(it) - } + "clearLiquids" -> modifier { filterNot { it is ConsumeLiquidBase || it is ConsumeLiquids }.toTypedArray() } + "liquid" -> modifier { this + TypeRegistry.resolve(it) } + "liquids" -> modifier { this + TypeRegistry.resolve(it) } + "liquidFlammable" -> modifier { this + TypeRegistry.resolve(it) } + "coolant" -> modifier { this + TypeRegistry.resolve(it) } - "powerBuffered" -> modifier { - this.filterNot { c -> c is ConsumePower }.toTypedArray() + ConsumePower(0f, it.asFloat(), true) - } + "clearPower" -> modifier { filterNot { it is ConsumePower }.toTypedArray() } + "power" -> modifier { + this.filterNot { c -> c is ConsumePower }.toTypedArray() + TypeRegistry.resolve(it) + } - else -> null + "powerBuffered" -> modifier { + this.filterNot { c -> c is ConsumePower }.toTypedArray() + ConsumePower(0f, it.asFloat(), true) } + + else -> null } - return null } override fun resolveType(json: JsonValue, type: Class?, elementType: Class<*>?, keyType: Class<*>?): T? { diff --git a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/ObjectMapItemNode.kt b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/ObjectMapItemNode.kt index 362d53e..4c8c764 100644 --- a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/ObjectMapItemNode.kt +++ b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/ObjectMapItemNode.kt @@ -7,11 +7,11 @@ import cf.wayzer.contentsTweaker.PatchHandler.Node import cf.wayzer.contentsTweaker.PatchHandler.withModifier import cf.wayzer.contentsTweaker.TypeRegistry -class ObjectMapItemNode(override val parent: Node, val mapKey: Any?, key: String) : Node(key), Node.Modifiable { +class ObjectMapItemNode(override val parent: Node, val mapKey: Any?, key: String) : Node(key), Node.Modifiable { @Suppress("UNCHECKED_CAST") - private val map = ((parent as WithObj).obj as ObjectMap) - override val type: Class<*>? - get() = (parent as WithObj).elementType ?: obj?.javaClass + private val map = ((parent as WithObj<*>).obj as ObjectMap) + override val type: Class<*> + get() = (parent as WithObj<*>).elementType ?: obj?.javaClass ?: Any::class.java override fun setValue(value: Any?) { map.put(mapKey, value) @@ -36,7 +36,7 @@ class ObjectMapItemNode(override val parent: Node, val mapKey: Any?, key: String companion object Resolver : PatchHandler.Resolver { override fun resolve(node: Node, child: String): Node? { - if (node !is WithObj) return null + if (node !is WithObj<*>) return null val obj = node.obj if (obj !is ObjectMap<*, *>) return null val keyType = node.keyType ?: (obj.keys().firstOrNull()?.javaClass) diff --git a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/ReflectNode.kt b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/ReflectNode.kt index 6e211c6..b0da4dc 100644 --- a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/ReflectNode.kt +++ b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/ReflectNode.kt @@ -6,21 +6,25 @@ import cf.wayzer.contentsTweaker.PatchHandler.Node import java.lang.reflect.Field -class ReflectNode(override val parent: Node, key: String, val field: Field) : Node(key), Node.Modifiable { - override val obj: Any = field.get((parent as WithObj).obj) - override val type: Class get() = this.field.type - private val typeMeta: FieldMetadata by lazy { this.field.let(::FieldMetadata) } +class ReflectNode(override val parent: Node, key: String, val f: Field) : Node(key), Node.Modifiable { + @Suppress("UNCHECKED_CAST") + override val obj: T get() = f.get((parent as WithObj<*>).obj) as T + + @Suppress("UNCHECKED_CAST") + override val type: Class get() = this.f.type as Class + private val typeMeta: FieldMetadata by lazy { this.f.let(::FieldMetadata) } override val elementType: Class<*>? get() = typeMeta.elementType override val keyType: Class<*>? get() = typeMeta.keyType override val storeDepth: Int get() = 0 + private val bak = obj override fun doSave() {}//already override fun doRecover() { - setValue(obj) + setValue(bak) } - override fun setValue(value: Any?) { - field.set((parent as WithObj).obj, value) + override fun setValue(value: T) { + f.set((parent as WithObj<*>).obj, value) } companion object Resolver : PatchHandler.Resolver { @@ -38,11 +42,11 @@ class ReflectNode(override val parent: Node, key: String, val field: Field) : No } override fun resolve(node: Node, child: String): Node? { - if (node !is WithObj) return null + if (node !is WithObj<*>) return null val obj = node.obj ?: return null val field = kotlin.runCatching { getField(obj, child) } .getOrNull() ?: return null - return ReflectNode(node, node.subKey(child), field) + return ReflectNode(node, node.subKey(child), field) } } } \ No newline at end of file diff --git a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/SeqResolver.kt b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/SeqResolver.kt index e6ba3f6..e974143 100644 --- a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/SeqResolver.kt +++ b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/SeqResolver.kt @@ -8,26 +8,25 @@ import cf.wayzer.contentsTweaker.TypeRegistry import mindustry.io.JsonIO object SeqResolver : PatchHandler.Resolver { - class SeqItemNode(override val parent: Node, val index: Int, key: String) : Node(key), Node.Modifiable { + class SeqItemNode(override val parent: Node, val index: Int, key: String) : Node(key), Node.Modifiable { @Suppress("UNCHECKED_CAST") - private val seq = (parent as WithObj).obj as Seq - - override val obj: Any? = seq.get(index) - override val type: Class<*>? - get() = (parent as WithObj).elementType ?: obj?.javaClass + private val seq = (parent as WithObj<*>).obj as Seq + override val obj: T get() = seq.get(index) + override val type: Class<*> get() = ((parent as WithObj<*>).elementType ?: obj.javaClass) override val storeDepth: Int get() = 0 + private val bak = obj override fun doSave() {} - override fun doRecover() = setValue(obj) + override fun doRecover() = setValue(bak) - override fun setValue(value: Any?) { + override fun setValue(value: T) { seq.set(index, value) } } - class AsModifiable(override val parent: Node, override val obj: Seq<*>, val deepCopy: Boolean) : Node(parent.key), Node.Modifiable { - private lateinit var backup: Seq<*> - override val type: Class<*> = Seq::class.java - override val elementType: Class<*>? = (parent as WithObj).elementType ?: obj.firstOrNull()?.javaClass + class AsModifiable(override val parent: Node, override val obj: Seq, val deepCopy: Boolean) : Node(parent.key), Node.Modifiable> { + private lateinit var backup: Seq + override val type: Class> = Seq::class.java + override val elementType: Class<*>? = (parent as WithObj<*>).elementType ?: obj.firstOrNull()?.javaClass override val storeDepth: Int get() = if (deepCopy) Int.MAX_VALUE else 0 override fun doSave() { @@ -41,41 +40,38 @@ object SeqResolver : PatchHandler.Resolver { setValue(backup) } - override fun setValue(value: Any?) { - @Suppress("UNCHECKED_CAST") - val value2 = value as Seq? + override fun setValue(value: Seq) { obj.clear() - if (value2 != null) - obj.addAll(value2) + obj.addAll(value) } } override fun resolve(node: Node, child: String): Node? { - if (node !is Node.WithObj) return null + if (node !is Node.WithObj<*>) return null val obj = node.obj if (obj !is Seq<*>) return null //通过数字索引 - child.toIntOrNull()?.let { return SeqItemNode(node, it, node.subKey(child)) } + child.toIntOrNull()?.let { return SeqItemNode(node, it, node.subKey(child)) } when (child) { "+=" -> { - if (node !is Node.Modifiable) error("${node.key} is Seq<*>, but not Modifiable, try use `asModifiable`") + if (node !is Node.Modifiable<*>) error("${node.key} is Seq<*>, but not Modifiable, try use `asModifiable`") return node.withModifier(child) { json -> val value = TypeRegistry.resolve>(json, elementType) beforeModify() @Suppress("UNCHECKED_CAST") - setValue(obj.copy().addAll(value as Seq)) + setValueAny(obj.copy().addAll(value as Seq)) } } //不支持-运算符,容易导致索引型的解析错误或者失败 "+" -> { - if (node !is Node.Modifiable) error("${node.key} is Seq<*>, but not Modifiable, try use `asModifiable`") + if (node !is Node.Modifiable<*>) error("${node.key} is Seq<*>, but not Modifiable, try use `asModifiable`") return node.withModifier(child) { json -> val value = TypeRegistry.resolveType(json, elementType) beforeModify() @Suppress("UNCHECKED_CAST") val parentSeq = obj as Seq - setValue(parentSeq.copy().add(value)) + setValueAny(parentSeq.copy().add(value)) } } diff --git a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/UIExtNode.kt b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/UIExtNode.kt index 6004668..e778674 100644 --- a/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/UIExtNode.kt +++ b/src/main/kotlin/cf/wayzer/contentsTweaker/resolvers/UIExtNode.kt @@ -14,6 +14,7 @@ import arc.scene.ui.layout.Table import arc.util.Align import cf.wayzer.contentsTweaker.PatchHandler import cf.wayzer.contentsTweaker.PatchHandler.withModifier +import mindustry.Vars import mindustry.gen.Call import mindustry.ui.Styles @@ -50,7 +51,7 @@ import mindustry.ui.Styles * } * ``` */ -open class UIExtNode(override val parent: PatchHandler.Node, key: String, val uiNode: Element) : PatchHandler.Node(key), PatchHandler.Node.WithObj { +open class UIExtNode(override val parent: PatchHandler.Node, key: String, val uiNode: Element) : PatchHandler.Node(key), PatchHandler.Node.WithObj { private var tableCell: Cell? = null val children = mutableMapOf() override val obj get() = uiNode @@ -157,7 +158,7 @@ open class UIExtNode(override val parent: PatchHandler.Node, key: String, val ui else -> null } - object Root : UIExtNode(PatchHandler.Node.Root, "uiExt.", Core.scene.root), Storable { + object Root : UIExtNode(PatchHandler.Node.Root, "uiExt.", Core.scene.root ?: Element()), Storable { override val storeDepth: Int = Int.MAX_VALUE override fun doSave() {} override fun doRecover() { @@ -167,8 +168,8 @@ open class UIExtNode(override val parent: PatchHandler.Node, key: String, val ui } companion object Resolver : PatchHandler.Resolver { - val alignMap = Align::class.java.declaredFields.associate { it.name to it.getInt(null) } - val stylesMap = Styles::class.java.declaredFields.associate { it.name to it.get(null)!! } + val alignMap by lazy { Align::class.java.declaredFields.associate { it.name to it.getInt(null) } } + val stylesMap by lazy { Styles::class.java.declaredFields.associate { it.name to it.get(null)!! } } fun createUIElement(type: String): Element = when (type) { "Table" -> Table() "Label" -> Label("") @@ -176,6 +177,7 @@ open class UIExtNode(override val parent: PatchHandler.Node, key: String, val ui } override fun resolve(node: PatchHandler.Node, child: String): PatchHandler.Node? { + if (Vars.headless) return null if (node == PatchHandler.Node.Root && child == "uiExt") return Root return null }