Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ static XBackupApi getInstance() {

static XBackupApi setInstance(XBackupApi instance) {
if (Instance.instance != null && instance != null) {
throw new IllegalStateException("Instance already set");
Instance.instance.close();
}
Instance.instance = instance;
return instance;
}

void close();

@NotNull Path getBlobFile(@NotNull String hash);

@Nullable IBackup getBackup(int id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ class BackupDatabaseService(
BackupTable.selectAll().count().toInt()
}

fun close() {
override fun close() {
syncExecutor.close()
TransactionManager.closeAndUnregister(database)
}
Expand Down
7 changes: 6 additions & 1 deletion common/src/main/resources/assets/x-backup/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,10 @@
"xb.gui.backups.restore_check_failed": "This backup is corrupted, cannot restore it!",
"xb.gui.backups.restored": "Backup restored successfully!",
"xb.gui.backups.title": "World Backups",
"xb.gui.no_polylib": "PolyLib is not installed, please install it to use the GUI."
"xb.gui.no_polylib": "PolyLib is not installed, please install it to use the GUI.",
"xb.gui.restore.title": "Restore Completed",
"xb.gui.restore.id": "Backup #%s",
"xb.gui.restore.comment": "Comment: %s",
"xb.gui.restore.close": "Back to Title",
"xb.gui.restore.reopen": "Reopen Save"
}
7 changes: 6 additions & 1 deletion common/src/main/resources/assets/x-backup/lang/zh_cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,10 @@
"xb.gui.backups.restore_check_failed": "此备份已损坏,无法回档!",
"xb.gui.backups.restored": "成功还原备份",
"xb.gui.backups.title": "备份列表",
"xb.gui.no_polylib": "未安装 PolyLib,请安装后使用 GUI 功能。"
"xb.gui.no_polylib": "未安装 PolyLib,请安装后使用 GUI 功能。",
"xb.gui.restore.title": "回档完成",
"xb.gui.restore.id": "备份 #%s",
"xb.gui.restore.comment": "备注: %s",
"xb.gui.restore.close": "返回标题界面",
"xb.gui.restore.reopen": "重新打开存档"
}
3 changes: 3 additions & 0 deletions src/main/kotlin/com/github/zly2006/xbackup/Commands.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.github.zly2006.xbackup.Utils.save
import com.github.zly2006.xbackup.Utils.send
import com.github.zly2006.xbackup.Utils.setAutoSaving
import com.github.zly2006.xbackup.api.IBackup
import com.github.zly2006.xbackup.gui.RestoreInfoScreen
import com.github.zly2006.xbackup.ktdsl.register
import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.arguments.IntegerArgumentType
Expand Down Expand Up @@ -739,6 +740,8 @@ object Commands {
XBackup.isBusy = false
XBackup.restoring = false
it.finishRestore()
} else if (!forceStop) {
Copy link

Copilot AI Jun 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the non-force-stop branch, it.finishRestore() is never called, so cleanup and notifications may not run. Consider moving or duplicating the it.finishRestore() call before opening the GUI to ensure the restore finalization always happens.

Suggested change
} else if (!forceStop) {
} else if (!forceStop) {
it.finishRestore()

Copilot uses AI. Check for mistakes.
RestoreInfoScreen.open(backup, path)
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/com/github/zly2006/xbackup/XBackup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ object XBackup : ModInitializer {
lateinit var config: Config
private val configPath = FabricLoader.getInstance().configDir.resolve("x-backup.config.json")
val log = LoggerFactory.getLogger("XBackup")!!
const val MOD_VERSION = /*$ mod_version*/ "0.3.11"
const val GIT_COMMIT = /*$ git_commit*/ "f1f683f"
const val COMMIT_DATE = /*$ commit_date*/ "2025-04-16T14:12:41+08:00"
const val MOD_VERSION = /*$ mod_version*/ "0.3.12"
const val GIT_COMMIT = /*$ git_commit*/ "7736a28"
const val COMMIT_DATE = /*$ commit_date*/ "2025-06-15T23:39:54+08:00"
var _service: BackupDatabaseService? = null
val service get() = _service!!
var server: MinecraftServer? = null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.github.zly2006.xbackup.gui

import com.github.zly2006.xbackup.XBackup
import com.github.zly2006.xbackup.api.IBackup
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.text.Text
import java.nio.file.Path
import kotlin.io.path.name

class RestoreInfoScreen(private val backup: IBackup, private val worldRoot: Path) : Screen(Text.translatable("xb.gui.restore.title")) {
private lateinit var reopenButton: ButtonWidget

override fun init() {
reopenButton = addDrawableChild(
ButtonWidget.builder(Text.translatable("xb.gui.restore.reopen")) {
reopenWorld()
}.dimensions(width / 2 - 75, height - 52, 150, 20).build()
)
addDrawableChild(
ButtonWidget.builder(Text.translatable("xb.gui.restore.close")) {
client?.setScreen(null)
}.dimensions(width / 2 - 75, height - 28, 150, 20).build()
)
}

override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
//? if >= 1.20.4 {
renderBackground(context, mouseX, mouseY, delta)
//?} else {
/*renderBackground(context)
*///?}
super.render(context, mouseX, mouseY, delta)
context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 20, 0xFFFFFF)
var y = height / 2 - 20
val idText = Text.translatable("xb.gui.restore.id", backup.id)
context.drawCenteredTextWithShadow(textRenderer, idText, width / 2, y, 0xFFFFFF)
y += 12
if (backup.comment.isNotEmpty()) {
val comment = Text.translatable("xb.gui.restore.comment", backup.comment)
context.drawCenteredTextWithShadow(textRenderer, comment, width / 2, y, 0xFFFFFF)
}

val progress = XBackup.service.activeTaskProgress
if (progress in 0..100) {
val barWidth = 150
val barHeight = 8
val x = (width - barWidth) / 2
val yBar = height / 2 + 20
context.fill(x, yBar, x + barWidth, yBar + barHeight, 0xFF555555.toInt())
val w = (barWidth * progress) / 100
if (w > 0) {
context.fill(x + 1, yBar + 1, x + w - 1, yBar + barHeight - 1, 0xFF00FF00.toInt())
}
context.drawCenteredTextWithShadow(textRenderer, Text.literal("$progress%"), width / 2, yBar - 10, 0xFFFFFF)
}
}

companion object {
fun open(backup: IBackup, worldRoot: Path) {
val client = MinecraftClient.getInstance()
client.execute { client.setScreen(RestoreInfoScreen(backup, worldRoot)) }
}
}

private fun reopenWorld() {
val client = MinecraftClient.getInstance()
client.setScreen(null)
runCatching {
val loader = client.createIntegratedServerLoader()
//? if >= 1.20.4 {
loader.start(worldRoot.normalize().name) {
this.close()
}
//?} else {
/*loader.start(this, worldRoot.normalize().name)
*///?}
}.onFailure { XBackup.log.error("Failed to reopen world", it) }
}
}