From a8ca3f62e09fc27b65d9c6790df96408fbb970c8 Mon Sep 17 00:00:00 2001 From: Jakob K Date: Mon, 13 May 2024 10:44:48 +0200 Subject: [PATCH] persistence: Ensure that CompoundSavedData always saves to file --- build.gradle.kts | 2 +- buildSrc/src/main/kotlin/BuildConstants.kt | 4 +-- .../mixin/other/MixinSavedData.java | 34 +++++++++++++++++++ .../silk/persistence/PersistentCompound.kt | 17 +++++++--- .../persistence/internal/CompoundSavedData.kt | 9 ++++- .../resources/silk-persistence.mixins.json | 1 + 6 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 silk-persistence/src/main/java/net/silkmc/silk/persistence/mixin/other/MixinSavedData.java diff --git a/build.gradle.kts b/build.gradle.kts index 7f1eec57..7bc66cab 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "net.silkmc" - version = "1.10.5" + version = "1.10.6" if (this.name.startsWith("silk")) { description = "Silk is a Minecraft API for Kotlin" } diff --git a/buildSrc/src/main/kotlin/BuildConstants.kt b/buildSrc/src/main/kotlin/BuildConstants.kt index 2fb22650..72adfd97 100644 --- a/buildSrc/src/main/kotlin/BuildConstants.kt +++ b/buildSrc/src/main/kotlin/BuildConstants.kt @@ -15,8 +15,8 @@ object BuildConstants { const val majorMinecraftVersion = "1.20" // check these values here: https://jakobk.net/mcdev - const val minecraftVersion = "1.20.5" - const val fabricLoaderVersion = "0.15.10" + const val minecraftVersion = "1.20.6" + const val fabricLoaderVersion = "0.15.11" const val fabricLanguageKotlinVersion = "1.10.19+kotlin.1.9.23" const val kotestVersion = "5.8.1" diff --git a/silk-persistence/src/main/java/net/silkmc/silk/persistence/mixin/other/MixinSavedData.java b/silk-persistence/src/main/java/net/silkmc/silk/persistence/mixin/other/MixinSavedData.java new file mode 100644 index 00000000..69e48f93 --- /dev/null +++ b/silk-persistence/src/main/java/net/silkmc/silk/persistence/mixin/other/MixinSavedData.java @@ -0,0 +1,34 @@ +package net.silkmc.silk.persistence.mixin.other; + +import net.minecraft.core.HolderLookup; +import net.minecraft.world.level.saveddata.SavedData; +import net.silkmc.silk.persistence.internal.CompoundSavedData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.io.File; + +@Mixin(SavedData.class) +public class MixinSavedData { + + @SuppressWarnings("UnreachableCode") + @Inject( + method = "save(Ljava/io/File;Lnet/minecraft/core/HolderLookup$Provider;)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/nbt/NbtUtils;addCurrentDataVersion(Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/nbt/CompoundTag;", + shift = At.Shift.BEFORE + ), + cancellable = true + ) + private void onSave(File file, HolderLookup.Provider provider, + CallbackInfo ci) { + if (((SavedData) (Object) this) instanceof CompoundSavedData compoundSavedData) { + if (compoundSavedData.getCompound().isEmpty() && !file.exists()) { + ci.cancel(); + } + } + } +} diff --git a/silk-persistence/src/main/kotlin/net/silkmc/silk/persistence/PersistentCompound.kt b/silk-persistence/src/main/kotlin/net/silkmc/silk/persistence/PersistentCompound.kt index a9fbd218..ae1a9e63 100644 --- a/silk-persistence/src/main/kotlin/net/silkmc/silk/persistence/PersistentCompound.kt +++ b/silk-persistence/src/main/kotlin/net/silkmc/silk/persistence/PersistentCompound.kt @@ -13,6 +13,12 @@ abstract class PersistentCompound { @PublishedApi internal val values = HashMap, Any>() + /** + * Returns whether this compound contains no data. + */ + val isEmpty: Boolean + get() = values.isEmpty() && (data?.isEmpty != false) + /** * Puts the given value into the persistent storage. * @@ -165,6 +171,8 @@ internal class PersistentCompoundImpl : PersistentCompound() { } override fun putInCompound(nbtCompound: CompoundTag, writeRaw: Boolean) { + if (isEmpty) return + val currentData = data!! for ((untypedKey, value) in values) { @@ -174,11 +182,10 @@ internal class PersistentCompoundImpl : PersistentCompound() { currentData.put(typedKey.name, typedKey.convertValueToNbtElement(value)) } - if (!currentData.isEmpty) { - if (writeRaw) - nbtCompound.merge(currentData) - else - nbtCompound.put(CUSTOM_DATA_KEY, currentData) + if (writeRaw) { + nbtCompound.merge(currentData) + } else { + nbtCompound.put(CUSTOM_DATA_KEY, currentData) } } } diff --git a/silk-persistence/src/main/kotlin/net/silkmc/silk/persistence/internal/CompoundSavedData.kt b/silk-persistence/src/main/kotlin/net/silkmc/silk/persistence/internal/CompoundSavedData.kt index 8c472c6e..66e5791a 100644 --- a/silk-persistence/src/main/kotlin/net/silkmc/silk/persistence/internal/CompoundSavedData.kt +++ b/silk-persistence/src/main/kotlin/net/silkmc/silk/persistence/internal/CompoundSavedData.kt @@ -8,7 +8,14 @@ import net.silkmc.silk.core.annotations.InternalSilkApi import net.silkmc.silk.persistence.PersistentCompound @InternalSilkApi -class CompoundSavedData(internal val compound: PersistentCompound) : SavedData() { +class CompoundSavedData(val compound: PersistentCompound) : SavedData() { + + // a compound does not track whether it is dirty, however custom + // logic is implemented via a mixin to prevent file creation for + // empty compounds + override fun isDirty(): Boolean { + return true + } override fun save(nbt: CompoundTag, provider: HolderLookup.Provider) = nbt.also { compound.putInCompound(it, writeRaw = true) } diff --git a/silk-persistence/src/main/resources/silk-persistence.mixins.json b/silk-persistence/src/main/resources/silk-persistence.mixins.json index 70e27bdf..001c0a3d 100644 --- a/silk-persistence/src/main/resources/silk-persistence.mixins.json +++ b/silk-persistence/src/main/resources/silk-persistence.mixins.json @@ -10,6 +10,7 @@ "chunk.ProtoChunkMixin", "entity.EntityMixin", "other.MixinDataFixTypes", + "other.MixinSavedData", "world.ServerWorldMixin" ] }