hopefully prevent fork bombs, fix #106
This commit is contained in:
parent
8cbcea2833
commit
63ea5822dd
3 changed files with 73 additions and 27 deletions
|
@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.spell.math.HexPattern
|
|||
import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidSpellDatumType
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.NbtUtils
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.chat.Component
|
||||
|
@ -30,20 +31,48 @@ import java.util.*
|
|||
class SpellDatum<T : Any> private constructor(val payload: T) {
|
||||
val clazz: Class<T> = payload.javaClass
|
||||
|
||||
fun serializeToNBT() = NBTBuilder {
|
||||
fun serializeToNBT(): CompoundTag = this.serializeToNBTWithDepthCheck(0, 0)?.first
|
||||
?: NBTBuilder { TAG_WIDGET %= Widget.GARBAGE.name }
|
||||
|
||||
|
||||
// The second int returned is the number of datums contained in this one.
|
||||
fun serializeToNBTWithDepthCheck(depth: Int, total: Int): Pair<CompoundTag, Int>? {
|
||||
if (total > MAX_SERIALIZATION_TOTAL)
|
||||
return null
|
||||
|
||||
val tag = NBTBuilder {
|
||||
when (val pl = payload) {
|
||||
is SpellList -> {
|
||||
// handle it specially!
|
||||
if (depth + 1 > MAX_SERIALIZATION_DEPTH) {
|
||||
return null
|
||||
}
|
||||
|
||||
val outList = ListTag()
|
||||
var total1 = total + 1 // make mutable and include the list itself
|
||||
for (elt in pl) {
|
||||
val (t, subtotal) = elt.serializeToNBTWithDepthCheck(depth + 1, total1) ?: return null
|
||||
total1 += subtotal
|
||||
outList.add(t)
|
||||
}
|
||||
return Pair(
|
||||
NBTBuilder { TAG_LIST %= outList },
|
||||
total1
|
||||
)
|
||||
}
|
||||
is Entity -> TAG_ENTITY %= compound {
|
||||
TAG_ENTITY_UUID %= NbtUtils.createUUID(pl.uuid)
|
||||
TAG_ENTITY_NAME_CHEATY %= Component.Serializer.toJson(pl.displayName)
|
||||
}
|
||||
is Double -> TAG_DOUBLE %= pl
|
||||
is Vec3 -> TAG_VEC3 %= pl.serializeToNBT()
|
||||
is SpellList -> TAG_LIST %= pl.serializeToNBT()
|
||||
is Widget -> TAG_WIDGET %= pl.name
|
||||
is HexPattern -> TAG_PATTERN %= pl.serializeToNBT()
|
||||
else -> throw RuntimeException("cannot serialize $pl because it is of type ${pl.javaClass.canonicalName} which is not serializable")
|
||||
}
|
||||
}
|
||||
return Pair(tag, 1)
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
buildString {
|
||||
|
@ -77,6 +106,9 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val MAX_SERIALIZATION_DEPTH = 256
|
||||
const val MAX_SERIALIZATION_TOTAL = 1024
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
||||
fun make(payload: Any): SpellDatum<*> =
|
||||
|
@ -200,7 +232,8 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
val subtag = nbt.getCompound(TAG_ENTITY)
|
||||
val json = subtag.getString(TAG_ENTITY_NAME_CHEATY)
|
||||
// handle pre-0.5.0 foci not having the tag
|
||||
out += Component.Serializer.fromJson(json)?.aqua ?: "hexcasting.spelldata.entity.whoknows".asTranslatedComponent.white
|
||||
out += Component.Serializer.fromJson(json)?.aqua
|
||||
?: "hexcasting.spelldata.entity.whoknows".asTranslatedComponent.white
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown key $key: $nbt")
|
||||
}
|
||||
|
|
|
@ -9,17 +9,17 @@ import net.minecraft.server.level.ServerLevel
|
|||
*
|
||||
* ...Surely this won't have any performance implications.
|
||||
*/
|
||||
sealed class SpellList: Iterable<SpellDatum<*>> {
|
||||
sealed class SpellList : Iterable<SpellDatum<*>> {
|
||||
|
||||
abstract val nonEmpty: Boolean
|
||||
abstract val car: SpellDatum<*>
|
||||
abstract val cdr: SpellList
|
||||
|
||||
class LPair(override val car: SpellDatum<*>, override val cdr: SpellList): SpellList() {
|
||||
class LPair(override val car: SpellDatum<*>, override val cdr: SpellList) : SpellList() {
|
||||
override val nonEmpty = true
|
||||
}
|
||||
|
||||
class LList(val idx: Int, val list: List<SpellDatum<*>>): SpellList() {
|
||||
class LList(val idx: Int, val list: List<SpellDatum<*>>) : SpellList() {
|
||||
override val nonEmpty: Boolean
|
||||
get() = idx < list.size
|
||||
override val car: SpellDatum<*>
|
||||
|
@ -69,7 +69,7 @@ sealed class SpellList: Iterable<SpellDatum<*>> {
|
|||
|
||||
override fun iterator() = SpellListIterator(this)
|
||||
|
||||
class SpellListIterator(var list: SpellList): Iterator<SpellDatum<*>> {
|
||||
class SpellListIterator(var list: SpellList) : Iterator<SpellDatum<*>> {
|
||||
override fun hasNext() = list.nonEmpty
|
||||
override operator fun next(): SpellDatum<*> {
|
||||
val car = list.car
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
@file:JvmName("HexUtils")
|
||||
|
||||
package at.petrak.hexcasting.api.utils
|
||||
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
import at.petrak.hexcasting.api.spell.math.HexCoord
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.LongArrayTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.chat.*
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
@ -179,14 +182,18 @@ interface WeakValue<T> {
|
|||
private class WeakReferencedValue<T>(var reference: WeakReference<T>?) : WeakValue<T> {
|
||||
override var value: T?
|
||||
get() = reference?.get()
|
||||
set(value) { reference = value?.let { WeakReference(it) } }
|
||||
set(value) {
|
||||
reference = value?.let { WeakReference(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private class WeakMappedValue<K, T>(val keyGen: (T) -> K) : WeakValue<T> {
|
||||
val reference = WeakHashMap<K, T>()
|
||||
override var value: T?
|
||||
get() = reference.values.firstOrNull()
|
||||
set(value) { if (value != null) reference[keyGen(value)] = value else reference.clear() }
|
||||
set(value) {
|
||||
if (value != null) reference[keyGen(value)] = value else reference.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> weakReference(value: T? = null): WeakValue<T> = WeakReferencedValue(value?.let { WeakReference(it) })
|
||||
|
@ -197,13 +204,19 @@ fun <T, K> weakMapped(keyGen: (T) -> K): WeakValue<T> = WeakMappedValue(keyGen)
|
|||
inline operator fun <T> WeakValue<T>.getValue(thisRef: Any?, property: KProperty<*>): T? = value
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline operator fun <T> WeakValue<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T?) { this.value = value }
|
||||
inline operator fun <T> WeakValue<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty list if it's too complicated.
|
||||
*/
|
||||
fun Iterable<SpellDatum<*>>.serializeToNBT(): ListTag {
|
||||
val tag = ListTag()
|
||||
for (elt in this)
|
||||
tag.add(elt.serializeToNBT())
|
||||
return tag
|
||||
val out = SpellDatum.make(SpellList.LList(0, this.toList())).serializeToNBT()
|
||||
return if (out.contains(SpellDatum.TAG_WIDGET))
|
||||
ListTag()
|
||||
else
|
||||
out.getList(SpellDatum.TAG_LIST, Tag.TAG_COMPOUND)
|
||||
}
|
||||
|
||||
// Copy the impl from forge
|
||||
|
|
Loading…
Reference in a new issue