summaryrefslogtreewikicommitdiff
path: root/core/src/game/MapSave.kt
blob: bead05bfd194dedb2b9e2d321f0f4dca42a8a9ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package cat.freya.khs.game

import cat.freya.khs.Khs
import cat.freya.khs.world.World
import java.io.File
import kotlin.error
import kotlin.io.deleteRecursively

private fun copyWorldFolder(
    plugin: Khs,
    map: KhsMap,
    loader: World.Loader,
    name: String,
    isMca: Boolean,
): Boolean {
    val dir = loader.dir
    val temp = loader.tempSaveDir

    val bounds = map.bounds() ?: return false

    val region = File(dir, name)
    val tempRegion = File(temp, name)

    if (!tempRegion.exists() && tempRegion.mkdirs() == false) {
        plugin.shim.logger.error("could not create directory: ${tempRegion.getPath()}")
        return false
    }

    val files = region.list()
    if (files == null) {
        plugin.shim.logger.error("could not access directory: ${region.getPath()}")
        return false
    }

    for (fileName in files) {
        val parts = fileName.split("\\.")
        if (isMca && parts.size > 1) {
            if (
                (parts[1].toInt() < bounds.minX / 512) ||
                    (parts[1].toInt() > bounds.maxX / 512) ||
                    (parts[2].toInt() < bounds.minZ / 512) ||
                    (parts[2].toInt() > bounds.maxZ / 512)
            )
                continue
        }

        val srcFile = File(region, fileName)
        if (srcFile.isDirectory()) {
            copyWorldFolder(plugin, map, loader, name + File.separator + fileName, false)
        } else {
            val destFile = File(tempRegion, fileName)
            srcFile.copyTo(destFile, overwrite = true)
        }
    }

    return true
}

private fun copyWorldFile(loader: World.Loader, name: String) {
    val dir = loader.dir
    val temp = loader.tempSaveDir

    val srcFile = File(dir, name)
    val destFile = File(temp, name)

    srcFile.copyTo(destFile, overwrite = true)
}

fun mapSave(plugin: Khs, map: KhsMap): Result<Unit> =
    runCatching {
            plugin.shim.logger.info("starting map save for: ${map.worldName}")
            plugin.saving = true

            plugin.shim.broadcast(plugin.locale.prefix.default + plugin.locale.map.save.start)
            plugin.shim.broadcast(plugin.locale.prefix.warning + plugin.locale.map.save.warning)

            if (plugin.config.mapSaveEnabled == false) error("map saves are disabled!")

            val loader = plugin.shim.getWorldLoader(map.worldName)
            val mapSaveLoader = plugin.shim.getWorldLoader(map.gameWorldName)
            val dir = loader.dir

            if (!dir.exists()) {
                plugin.shim.broadcast(
                    plugin.locale.prefix.error + plugin.locale.map.save.failedLocate
                )
                error("there is no map to save")
            }

            mapSaveLoader.unload()

            copyWorldFolder(plugin, map, loader, "region", true)
            copyWorldFolder(plugin, map, loader, "entities", true)
            copyWorldFolder(plugin, map, loader, "datapacks", false)
            copyWorldFolder(plugin, map, loader, "data", false)
            copyWorldFile(loader, "level.dat")

            val dest = mapSaveLoader.dir
            if (dest.exists() && !dest.deleteRecursively()) {
                plugin.shim.broadcast(
                    plugin.locale.prefix.error +
                        plugin.locale.map.save.failedDir.with(dest.toPath())
                )
                error("could not delete destination directory")
            }

            val tempDest = loader.tempSaveDir
            if (!tempDest.renameTo(dest)) {
                plugin.shim.broadcast(
                    plugin.locale.prefix.error +
                        plugin.locale.map.save.failedDir.with(tempDest.toPath())
                )
                error("could not rename: ${tempDest.toPath()}")
            }
        }
        .onSuccess {
            plugin.saving = false
            plugin.shim.broadcast(plugin.locale.prefix.default + plugin.locale.map.save.finished)
        }
        .onFailure {
            plugin.saving = false
            plugin.shim.broadcast(
                plugin.locale.prefix.error +
                    plugin.locale.map.save.failed.with(it.message ?: "unknown error")
            )
        }