Skip to content

Commit

Permalink
Dont use inline class for PrefabKey, string operations are slower
Browse files Browse the repository at this point in the history
  • Loading branch information
0ffz committed Aug 21, 2022
1 parent 0777f4f commit c255177
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ import org.koin.core.component.KoinComponent
* by a '`:`' symbol.
*/
@Serializable(with = PrefabKeySerializer::class)
@JvmInline
value class PrefabKey private constructor(val full: String) : KoinComponent {
val namespace: String get() = full.substringBefore(':')
val key: String get() = full.substringAfter(':')

// We don't make this a value class since calculating substring is pretty expensive compared to one new object instantiation
class PrefabKey private constructor(val namespace: String, val key: String) : KoinComponent {
fun toEntity(): Entity = toEntityOrNull()
?: error("Requested non null prefab entity for $this, but it does not exist.")

fun toEntityOrNull(): Entity? = globalContext.prefabManager[this]

val full get() = "$namespace:$key"

override fun toString(): String = full

companion object {
Expand All @@ -29,9 +28,10 @@ value class PrefabKey private constructor(val full: String) : KoinComponent {

/** Creates a key from a string with [namespace] and [key] separated by one '`:`' character. */
fun of(stringKey: String): PrefabKey {
if (stringKey.split(':').size != 2)
val split = stringKey.split(':')
if (split.size != 2)
error("Malformed prefab key: $stringKey. Must only contain one : that splits namespace and key.")
return PrefabKey(stringKey)
return PrefabKey(split[0], split[1])
}

/** Creates a key from a [namespace] and [name] which must not contain any '`:`' characters. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ inline fun <reified T : GearyComponent> PersistentDataContainer.decode(): T? {
inline fun <reified T : GearyComponent> PersistentDataContainer.decode(
key: NamespacedKey,
serializer: DeserializationStrategy<out T>? =
globalContext.serializers.getSerializerFor(key.removeComponentPrefix(), T::class)
globalContext.serializers.getSerializerFor(key, T::class)
): T? {

serializer ?: return null
Expand Down Expand Up @@ -92,6 +92,8 @@ fun PersistentDataContainer.encodeComponents(
encodePrefabs(prefabs.map { it.toRelation()!!.target.toGeary().get<PrefabKey>() }.filterNotNull())
}

private val PREFABS_KEY = "geary:prefabs".toMCKey()

/**
* Encodes a list of [PrefabKey]s under the key `geary:prefabs`. When decoding these will be stored in
* [DecodedEntityData.type].
Expand All @@ -104,7 +106,7 @@ fun PersistentDataContainer.encodePrefabs(keys: Collection<PrefabKey>) {
encode(
keys.toSet(),
SetSerializer(PrefabKey.serializer()),
"geary:prefabs".toMCKey()
PREFABS_KEY
)
}

Expand All @@ -113,7 +115,7 @@ object PrefabNamespaceMigrations {
}

fun PersistentDataContainer.decodePrefabs(): Set<PrefabKey> =
decode("geary:prefabs".toMCKey(), SetSerializer(PrefabKey.serializer()))
decode(PREFABS_KEY, SetSerializer(PrefabKey.serializer()))
?.map { key ->
// Migrate namespace if needed
val migrated = PrefabNamespaceMigrations.migrations.getOrDefault(key.namespace, key.namespace)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,19 @@ import org.bukkit.NamespacedKey
import org.bukkit.persistence.PersistentDataContainer
import org.bukkit.plugin.Plugin

/** The prefix present for keys of component [NamespacedKey]s. (i.e. `namespace:COMPONENT_PREFIX.key`) */
internal const val COMPONENT_PREFIX = "component."

/** Gets all the keys under this [PersistentDataContainer] whose namespace matches the [plugin]'s. */
internal fun PersistentDataContainer.keysFrom(plugin: Plugin): List<NamespacedKey> {
val pluginNamespace = NamespacedKey(plugin, "").namespace
return keys.filter { it.namespace == pluginNamespace }
}

/** Converts this string to a [NamespacedKey] with the [COMPONENT_PREFIX] on its key. */
public fun String.toComponentKey(): NamespacedKey = toMCKey().addComponentPrefix()
fun String.toComponentKey(): NamespacedKey =
if (this.startsWith(COMPONENT_PREFIX)) toMCKey()
else "$COMPONENT_PREFIX$this".toMCKey()

/** Gets the serialName associated with this component [NamespacedKey]. */
public fun NamespacedKey.toSerialName(): String = "$namespace:${key.removePrefix(COMPONENT_PREFIX)}"

/** The prefix present for keys of component [NamespacedKey]s. (i.e. `namespace:COMPONENT_PREFIX.key`) */
internal const val COMPONENT_PREFIX = "component."

/** Adds the [COMPONENT_PREFIX] to this [NamespacedKey] if not already present. */
public fun NamespacedKey.addComponentPrefix(): NamespacedKey {
if (key.startsWith(COMPONENT_PREFIX)) return this

@Suppress("DEPRECATION")
return NamespacedKey(namespace, "$COMPONENT_PREFIX${key}")
}

public fun NamespacedKey.removeComponentPrefix(): NamespacedKey {
if (!key.startsWith(COMPONENT_PREFIX)) return this

@Suppress("DEPRECATION")
return NamespacedKey(namespace, key.removePrefix(COMPONENT_PREFIX))
}
fun NamespacedKey.toSerialName(): String = "$namespace:${key.removePrefix(COMPONENT_PREFIX)}"

0 comments on commit c255177

Please sign in to comment.