Skip to content

Commit e83873a

Browse files
feat: implement worlds and world folders arguments in WorldCommand
1 parent 8677ea8 commit e83873a

File tree

4 files changed

+162
-36
lines changed

4 files changed

+162
-36
lines changed

src/main/kotlin/dev/slne/surf/essentials/command/WorldCommand.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package dev.slne.surf.essentials.command
22

33
import dev.jorel.commandapi.kotlindsl.*
4+
import dev.slne.surf.essentials.command.argument.world.worldFoldersArgument
5+
import dev.slne.surf.essentials.command.argument.world.worldsArgument
46
import dev.slne.surf.essentials.service.worldService
57
import dev.slne.surf.essentials.util.permission.EssentialsPermissionRegistry
68
import dev.slne.surf.essentials.util.util.isFolia
@@ -12,7 +14,7 @@ fun worldCommand() = commandTree("world") {
1214
withPermission(EssentialsPermissionRegistry.WORLD_COMMAND)
1315

1416
literalArgument("lock") {
15-
worldArgument("world") {
17+
worldsArgument("world") {
1618
withPermission(EssentialsPermissionRegistry.WORLD_COMMAND_LOCK)
1719
anyExecutor { executor, args ->
1820
val world: World by args
@@ -45,7 +47,7 @@ fun worldCommand() = commandTree("world") {
4547
}
4648

4749
literalArgument("unlock") {
48-
worldArgument("world") {
50+
worldsArgument("world") {
4951
withPermission(EssentialsPermissionRegistry.WORLD_COMMAND_UNLOCK)
5052
anyExecutor { executor, args ->
5153
val world: World by args
@@ -78,7 +80,7 @@ fun worldCommand() = commandTree("world") {
7880
}
7981

8082
literalArgument("join") {
81-
worldArgument("world") {
83+
worldsArgument("world") {
8284
withPermission(EssentialsPermissionRegistry.WORLD_COMMAND_JOIN)
8385
playerExecutor { player, args ->
8486
val world: World by args
@@ -122,7 +124,7 @@ fun worldCommand() = commandTree("world") {
122124
}
123125

124126
literalArgument("delete") {
125-
worldArgument("world") {
127+
worldsArgument("world") {
126128
withPermission(EssentialsPermissionRegistry.WORLD_COMMAND_DELETE)
127129
anyExecutor { executor, args ->
128130
val world: World by args
@@ -141,7 +143,7 @@ fun worldCommand() = commandTree("world") {
141143
}
142144

143145
literalArgument("load") {
144-
stringArgument("name") {
146+
worldFoldersArgument("name") {
145147
withPermission(EssentialsPermissionRegistry.WORLD_COMMAND_LOAD)
146148
anyExecutor { executor, args ->
147149
val name: String by args
@@ -161,7 +163,7 @@ fun worldCommand() = commandTree("world") {
161163
}
162164

163165
literalArgument("unload") {
164-
worldArgument("world") {
166+
worldsArgument("world") {
165167
withPermission(EssentialsPermissionRegistry.WORLD_COMMAND_UNLOAD)
166168
anyExecutor { executor, args ->
167169
val world: World by args
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package dev.slne.surf.essentials.command.argument.world
2+
3+
import dev.jorel.commandapi.CommandTree
4+
import dev.jorel.commandapi.arguments.Argument
5+
import dev.jorel.commandapi.arguments.ArgumentSuggestions
6+
import dev.jorel.commandapi.arguments.CustomArgument
7+
import dev.jorel.commandapi.arguments.StringArgument
8+
import dev.slne.surf.surfapi.core.api.messages.adventure.buildText
9+
import org.bukkit.Bukkit
10+
import org.bukkit.command.CommandSender
11+
import java.io.File
12+
13+
class WorldFoldersArgument(nodeName: String) :
14+
CustomArgument<String, String>(StringArgument(nodeName), { info ->
15+
if (File(Bukkit.getWorldContainer(), info.input).exists()) {
16+
info.input
17+
} else {
18+
throw CustomArgumentException.fromAdventureComponent {
19+
buildText {
20+
appendPrefix()
21+
error("Der Welten-Ordner wurde nicht gefunden.")
22+
}
23+
}
24+
}
25+
}) {
26+
init {
27+
this.replaceSuggestions(
28+
ArgumentSuggestions.stringCollection<CommandSender> {
29+
Bukkit.getWorldContainer().listFiles().filter { isMinecraftWorldFolder(it) }
30+
.map { it.name }
31+
}
32+
)
33+
}
34+
}
35+
36+
private fun isMinecraftWorldFolder(folder: File): Boolean {
37+
if (!folder.isDirectory) return false
38+
39+
val levelDat = File(folder, "level.dat")
40+
val regionFolder = File(folder, "region")
41+
42+
return levelDat.exists() && regionFolder.exists() && regionFolder.isDirectory
43+
}
44+
45+
46+
inline fun CommandTree.worldFoldersArgument(
47+
nodeName: String,
48+
optional: Boolean = false,
49+
block: Argument<*>.() -> Unit = {}
50+
): CommandTree = then(
51+
WorldFoldersArgument(nodeName).setOptional(optional).apply(block)
52+
)
53+
54+
inline fun Argument<*>.worldFoldersArgument(
55+
nodeName: String,
56+
optional: Boolean = false,
57+
block: Argument<*>.() -> Unit = {}
58+
): Argument<*> = then(
59+
WorldFoldersArgument(nodeName).setOptional(optional).apply(block)
60+
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package dev.slne.surf.essentials.command.argument.world
2+
3+
import dev.jorel.commandapi.CommandTree
4+
import dev.jorel.commandapi.arguments.Argument
5+
import dev.jorel.commandapi.arguments.ArgumentSuggestions
6+
import dev.jorel.commandapi.arguments.CustomArgument
7+
import dev.jorel.commandapi.arguments.StringArgument
8+
import dev.slne.surf.surfapi.core.api.messages.adventure.buildText
9+
import org.bukkit.Bukkit
10+
import org.bukkit.World
11+
import org.bukkit.command.CommandSender
12+
13+
class WorldsArgument(nodeName: String) :
14+
CustomArgument<World, String>(StringArgument(nodeName), { info ->
15+
Bukkit.getWorld(info.input) ?: throw CustomArgumentException.fromAdventureComponent {
16+
buildText {
17+
appendPrefix()
18+
error("Die Welt wurde nicht gefunden.")
19+
}
20+
}
21+
}) {
22+
init {
23+
this.replaceSuggestions(
24+
ArgumentSuggestions.stringCollection<CommandSender> {
25+
Bukkit.getWorlds().map { it.name }
26+
}
27+
)
28+
}
29+
}
30+
31+
inline fun CommandTree.worldsArgument(
32+
nodeName: String,
33+
optional: Boolean = false,
34+
block: Argument<*>.() -> Unit = {}
35+
): CommandTree = then(
36+
WorldsArgument(nodeName).setOptional(optional).apply(block)
37+
)
38+
39+
inline fun Argument<*>.worldsArgument(
40+
nodeName: String,
41+
optional: Boolean = false,
42+
block: Argument<*>.() -> Unit = {}
43+
): Argument<*> = then(
44+
WorldsArgument(nodeName).setOptional(optional).apply(block)
45+
)

src/main/kotlin/dev/slne/surf/essentials/service/WorldService.kt

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import dev.slne.surf.surfapi.core.api.messages.adventure.sendText
66
import org.bukkit.*
77
import org.bukkit.command.CommandSender
88
import org.bukkit.persistence.PersistentDataType
9+
import java.util.concurrent.CompletableFuture
910

1011
class WorldService {
1112
private val accessKey = NamespacedKey(plugin, "world_access")
@@ -137,23 +138,37 @@ class WorldService {
137138
return
138139
}
139140

140-
world.players.forEach {
141-
it.teleportAsync(overworldSpawn)
141+
val futures = mutableListOf<CompletableFuture<Boolean>>()
142+
143+
sender.sendText {
144+
appendPrefix()
145+
info("Teleporiere Spieler aus der Welt...")
142146
}
143147

144-
if (!Bukkit.unloadWorld(world, true)) {
145-
sender.sendText {
146-
appendPrefix()
147-
error("Die Welt konnte nicht entladen werden.")
148-
}
149-
return
148+
world.players.forEach {
149+
futures.add(it.teleportAsync(overworldSpawn))
150150
}
151151

152152
sender.sendText {
153153
appendPrefix()
154-
success("Die Welt ")
155-
variableValue(world.name)
156-
success(" wurde entladen.")
154+
info("Die Welt wird entladen...")
155+
}
156+
157+
CompletableFuture.allOf(*futures.toTypedArray()).thenRun {
158+
if (!Bukkit.unloadWorld(world, true)) {
159+
sender.sendText {
160+
appendPrefix()
161+
error("Die Welt konnte nicht entladen werden.")
162+
}
163+
return@thenRun
164+
}
165+
166+
sender.sendText {
167+
appendPrefix()
168+
success("Die Welt ")
169+
variableValue(world.name)
170+
success(" wurde entladen.")
171+
}
157172
}
158173
}
159174

@@ -174,36 +189,40 @@ class WorldService {
174189
return
175190
}
176191

192+
val futures = mutableListOf<CompletableFuture<Boolean>>()
193+
177194
world.players.forEach {
178-
it.teleportAsync(overworldSpawn)
195+
futures.add(it.teleportAsync(overworldSpawn))
179196
}
180197

181-
if (Bukkit.getWorld(world.name) != null) {
182-
if (!Bukkit.unloadWorld(world, true)) {
198+
CompletableFuture.allOf(*futures.toTypedArray()).thenRun {
199+
if (Bukkit.getWorld(world.name) != null) {
200+
if (!Bukkit.unloadWorld(world, true)) {
201+
sender.sendText {
202+
appendPrefix()
203+
error("Die Welt konnte nicht entladen werden.")
204+
}
205+
return@thenRun
206+
}
207+
}
208+
209+
val file = Bukkit.getWorldContainer().resolve(world.name)
210+
if (!file.exists() || !file.isDirectory) {
183211
sender.sendText {
184212
appendPrefix()
185-
error("Die Welt konnte nicht entladen werden.")
213+
error("Die Welt existiert nicht.")
186214
}
187-
return
215+
return@thenRun
188216
}
189-
}
190217

191-
val file = Bukkit.getWorldContainer().resolve(world.name)
192-
if (!file.exists() || !file.isDirectory) {
218+
file.deleteRecursively()
219+
193220
sender.sendText {
194221
appendPrefix()
195-
error("Die Welt existiert nicht.")
222+
success("Die Welt ")
223+
variableValue(world.name)
224+
success(" wurde gelöscht.")
196225
}
197-
return
198-
}
199-
200-
file.deleteRecursively()
201-
202-
sender.sendText {
203-
appendPrefix()
204-
success("Die Welt ")
205-
variableValue(world.name)
206-
success(" wurde gelöscht.")
207226
}
208227
}
209228

0 commit comments

Comments
 (0)