Skip to content

Commit 81b4bb1

Browse files
authored
Config file tracking (#819)
* Update config files to track file changes * Remove print statement * Test fix * Add missing properties
1 parent 0cff4ca commit 81b4bb1

File tree

17 files changed

+94
-35
lines changed

17 files changed

+94
-35
lines changed

cache/src/main/kotlin/world/gregs/voidps/cache/FileCache.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ class FileCache(
3636
}
3737

3838
override fun data(index: Int, archive: Int, file: Int, xtea: IntArray?): ByteArray? {
39-
println("DATA ${files.size}")
4039
if (index >= files.size) {
4140
return null
4241
}

engine/src/main/kotlin/world/gregs/voidps/engine/data/ConfigFiles.kt

Lines changed: 81 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,109 @@ package world.gregs.voidps.engine.data
22

33
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
44
import it.unimi.dsi.fastutil.objects.ObjectArrayList
5+
import world.gregs.voidps.buffer.read.ArrayReader
6+
import world.gregs.voidps.buffer.write.ArrayWriter
57
import world.gregs.voidps.engine.timedLoad
8+
import java.io.File
69
import java.nio.file.Files
710
import java.nio.file.NoSuchFileException
811
import java.nio.file.Path
12+
import kotlin.io.path.exists
13+
import kotlin.io.path.extension
914
import kotlin.io.path.isDirectory
1015
import kotlin.io.path.name
1116
import kotlin.io.path.pathString
17+
import kotlin.io.path.readBytes
18+
import kotlin.io.path.writeBytes
1219

13-
typealias ConfigFiles = Map<String, List<String>>
20+
data class ConfigFiles(
21+
val map: Map<String, List<String>>,
22+
val cacheUpdate: Boolean = false,
23+
val extensions: Set<String> = emptySet(),
24+
) {
25+
fun list(path: String): List<String> = map.getOrDefault(path, emptyList())
1426

15-
fun ConfigFiles.list(path: String): List<String> = getOrDefault(path, emptyList())
27+
fun getValue(key: String) = map.getValue(key)
1628

17-
fun ConfigFiles.find(path: String, type: String = "toml"): String = getOrDefault(type, emptyList()).firstOrNull { it.endsWith(path) } ?: throw NoSuchFileException("Unable to find config file '$path' in /data/ directory.")
29+
fun find(path: String, type: String = "toml"): String = map.getOrDefault(type, emptyList()).firstOrNull { it.endsWith(path) } ?: throw NoSuchFileException("Unable to find config file '$path' in /data/ directory.")
30+
}
31+
32+
fun tempCache(cachePath: String = Settings["storage.cache.temp.path"]): File? {
33+
if (!Settings["storage.cache.temp.active", false]) {
34+
return null
35+
}
36+
val directory = File(cachePath)
37+
if (!directory.exists()) {
38+
directory.mkdirs()
39+
}
40+
return directory
41+
}
1842

1943
fun configFiles(): ConfigFiles {
2044
val map = Object2ObjectOpenHashMap<String, MutableList<String>>()
45+
val path = Path.of(Settings["storage.data"])
46+
val modified = Path.of(Settings["storage.data.modified"])
47+
val lastUpdated = loadLastUpdate(modified)
48+
val extensions = mutableSetOf<String>()
2149
timedLoad("config file paths") {
22-
walkPath(map, Path.of(Settings["storage.data"]))
50+
walkPath(map, path, lastUpdated, extensions)
51+
map.size
2352
}
24-
return map
53+
return ConfigFiles(map, cacheChanged(lastUpdated), extensions)
2554
}
2655

27-
private fun walkPath(map: MutableMap<String, MutableList<String>>, dir: Path): Int {
28-
// Exclusions
56+
fun updateModified() {
57+
val modified = Path.of(Settings["storage.data.modified"])
58+
val writer = ArrayWriter(8)
59+
writer.writeLong(System.currentTimeMillis())
60+
modified.writeBytes(writer.toArray())
61+
}
62+
63+
private fun loadLastUpdate(path: Path): Long {
64+
if (path.exists()) {
65+
val reader = ArrayReader(path.readBytes())
66+
return reader.readLong()
67+
}
68+
return 0
69+
}
70+
71+
private fun walkPath(
72+
map: MutableMap<String, MutableList<String>>,
73+
dir: Path,
74+
lastUpdated: Long,
75+
invalidatedExtensions: MutableSet<String>,
76+
) {
2977
val name = dir.name
3078
if (name == "saves" || name == "players" || name == "cache") {
31-
return 0
79+
return
3280
}
33-
var count = 0
3481
for (path in Files.newDirectoryStream(dir)) {
3582
if (path.isDirectory()) {
36-
count += walkPath(map, path)
37-
} else {
38-
val extension = path.name.substringAfter('.')
39-
count++
40-
map.getOrPut(extension) { ObjectArrayList() }.add(path.pathString)
83+
walkPath(map, path, lastUpdated, invalidatedExtensions)
84+
continue
85+
}
86+
val extension = path.name.substringAfter('.')
87+
map.getOrPut(extension) { ObjectArrayList() }.add(path.pathString)
88+
89+
// Check file-type hasn't been marked as invalidated before checking the last modified time for invalidation
90+
if (!invalidatedExtensions.contains(extension) && Files.getLastModifiedTime(path).toMillis() > lastUpdated) {
91+
invalidatedExtensions.add(extension)
4192
}
4293
}
43-
return count
4494
}
95+
96+
private fun cacheChanged(
97+
lastUpdated: Long,
98+
dir: Path = Path.of(Settings["storage.cache.path"]),
99+
): Boolean {
100+
for (path in Files.newDirectoryStream(dir)) {
101+
if (path.isDirectory() || (!path.extension.startsWith("dat") && !path.extension.startsWith("idx"))) {
102+
continue
103+
}
104+
val lastModified = Files.getLastModifiedTime(path).toMillis()
105+
if (lastModified > lastUpdated) {
106+
return true
107+
}
108+
}
109+
return false
110+
}

engine/src/main/kotlin/world/gregs/voidps/engine/data/definition/MapDefinitions.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import world.gregs.voidps.engine.client.ui.chat.plural
1010
import world.gregs.voidps.engine.client.update.batch.ZoneBatchUpdates
1111
import world.gregs.voidps.engine.data.Settings
1212
import world.gregs.voidps.engine.data.configFiles
13-
import world.gregs.voidps.engine.data.list
1413
import world.gregs.voidps.engine.entity.obj.GameObjects
1514
import world.gregs.voidps.engine.map.collision.CollisionDecoder
1615
import world.gregs.voidps.engine.map.collision.Collisions

engine/src/main/kotlin/world/gregs/voidps/engine/entity/World.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import org.koin.core.component.KoinComponent
55
import world.gregs.voidps.engine.GameLoop
66
import world.gregs.voidps.engine.client.variable.VariableStore
77
import world.gregs.voidps.engine.client.variable.Variables
8+
import world.gregs.voidps.engine.data.ConfigFiles
89
import world.gregs.voidps.engine.data.Settings
9-
import world.gregs.voidps.engine.data.list
1010
import world.gregs.voidps.engine.entity.character.npc.NPCs
1111
import world.gregs.voidps.engine.entity.character.npc.loadNpcSpawns
1212
import world.gregs.voidps.engine.entity.item.floor.FloorItems
@@ -32,7 +32,7 @@ object World : Entity, VariableStore, Runnable, KoinComponent {
3232
val members: Boolean
3333
get() = Settings["world.members", false]
3434

35-
fun start(files: Map<String, List<String>>) {
35+
fun start(files: ConfigFiles) {
3636
loadItemSpawns(get<FloorItems>(), get<ItemSpawns>(), files.list(Settings["spawns.items"]), get())
3737
loadObjectSpawns(get<GameObjects>(), files.list(Settings["spawns.objects"]), get())
3838
loadNpcSpawns(get<NPCs>(), files.list(Settings["spawns.npcs"]), get())

engine/src/test/kotlin/world/gregs/voidps/engine/entity/SpawnTest.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import world.gregs.voidps.cache.definition.data.ObjectDefinition
99
import world.gregs.voidps.engine.Caller
1010
import world.gregs.voidps.engine.Script
1111
import world.gregs.voidps.engine.ScriptTest
12+
import world.gregs.voidps.engine.data.ConfigFiles
1213
import world.gregs.voidps.engine.data.definition.ObjectDefinitions
1314
import world.gregs.voidps.engine.entity.character.npc.NPC
1415
import world.gregs.voidps.engine.entity.character.player.Player
@@ -135,7 +136,7 @@ class SpawnTest {
135136
}
136137

137138
override fun invoke(args: List<String>) {
138-
Spawn.world(mapOf())
139+
Spawn.world(ConfigFiles(mapOf()))
139140
}
140141

141142
override val apis = listOf(Spawn)

game/src/main/kotlin/content/activity/penguin_hide_and_seek/PenguinHideAndSeek.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import world.gregs.voidps.engine.data.Settings
1919
import world.gregs.voidps.engine.data.configFiles
2020
import world.gregs.voidps.engine.data.definition.AccountDefinitions
2121
import world.gregs.voidps.engine.data.definition.AreaDefinitions
22-
import world.gregs.voidps.engine.data.find
2322
import world.gregs.voidps.engine.entity.World
2423
import world.gregs.voidps.engine.entity.character.npc.NPC
2524
import world.gregs.voidps.engine.entity.character.npc.NPCs

game/src/main/kotlin/content/entity/player/command/ServerCommands.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ import world.gregs.voidps.engine.data.definition.RenderEmoteDefinitions
3434
import world.gregs.voidps.engine.data.definition.SoundDefinitions
3535
import world.gregs.voidps.engine.data.definition.SpellDefinitions
3636
import world.gregs.voidps.engine.data.definition.VariableDefinitions
37-
import world.gregs.voidps.engine.data.find
38-
import world.gregs.voidps.engine.data.list
3937
import world.gregs.voidps.engine.entity.World
4038
import world.gregs.voidps.engine.entity.character.npc.NPCs
4139
import world.gregs.voidps.engine.entity.character.npc.loadNpcSpawns

game/src/main/resources/game.properties

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ storage.autoSave.minutes=5
233233
# The base directory for all game config data
234234
storage.data=./data/
235235

236+
# File storing timestamp of when config files or cache last changed
237+
storage.data.modified=./data/modified.dat
238+
236239
# The directory where player save files are stored
237240
storage.players.path=./data/saves/
238241

@@ -251,6 +254,12 @@ storage.wildcards=./data/wildcards.txt
251254
# The directory where game cache data is stored
252255
storage.cache.path=./data/cache/
253256

257+
# Whether to use more memory to store temporary files for faster loading
258+
storage.cache.temp.active=true
259+
260+
# Directory where temporary cached files are stored
261+
storage.cache.temp.path=./data/cache/temp/
262+
254263
# The type of file server backend (options: internal, external)
255264
storage.cache.server=internal
256265

game/src/test/kotlin/content/entity/player/inv/DropTest.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import org.junit.jupiter.api.Assertions.assertTrue
99
import org.junit.jupiter.api.Test
1010
import world.gregs.voidps.engine.data.Settings
1111
import world.gregs.voidps.engine.data.configFiles
12-
import world.gregs.voidps.engine.data.list
1312
import world.gregs.voidps.engine.entity.item.Item
1413
import world.gregs.voidps.engine.entity.item.floor.FloorItems
1514
import world.gregs.voidps.engine.entity.item.floor.ItemSpawns

game/src/test/kotlin/content/quest/free/cooks_assistant/CooksAssistantTest.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import world.gregs.voidps.engine.client.instruction.handle.interactFloorItem
1414
import world.gregs.voidps.engine.client.instruction.handle.interactObject
1515
import world.gregs.voidps.engine.client.ui.dialogue
1616
import world.gregs.voidps.engine.data.Settings
17-
import world.gregs.voidps.engine.data.list
1817
import world.gregs.voidps.engine.entity.character.move.tele
1918
import world.gregs.voidps.engine.entity.character.player.Player
2019
import world.gregs.voidps.engine.entity.item.floor.loadItemSpawns

0 commit comments

Comments
 (0)