diff --git a/src/main/kotlin/one/oktw/galaxy/proxy/Main.kt b/src/main/kotlin/one/oktw/galaxy/proxy/Main.kt index 62c4dff..286d8c8 100644 --- a/src/main/kotlin/one/oktw/galaxy/proxy/Main.kt +++ b/src/main/kotlin/one/oktw/galaxy/proxy/Main.kt @@ -2,6 +2,7 @@ package one.oktw.galaxy.proxy import com.google.inject.Inject import com.velocitypowered.api.event.Subscribe +import com.velocitypowered.api.event.connection.DisconnectEvent import com.velocitypowered.api.event.player.KickedFromServerEvent import com.velocitypowered.api.event.player.ServerPostConnectEvent import com.velocitypowered.api.event.player.ServerPreConnectEvent @@ -23,7 +24,7 @@ import one.oktw.galaxy.proxy.event.TabListUpdater import one.oktw.galaxy.proxy.kubernetes.KubernetesClient import one.oktw.galaxy.proxy.pubsub.Manager import one.oktw.galaxy.proxy.redis.RedisClient -import one.oktw.galaxy.proxy.resourcepack.ResourcePackHelper +import one.oktw.galaxy.proxy.resourcepack.ResourcePackManager import org.slf4j.Logger import java.net.InetSocketAddress import kotlin.system.exitProcess @@ -53,6 +54,8 @@ class Main : CoroutineScope by CoroutineScope(Dispatchers.Default + SupervisorJo private set lateinit var manager: Manager private set + lateinit var resourcePackManager: ResourcePackManager + private set @Inject fun init(proxy: ProxyServer, logger: Logger) { @@ -63,6 +66,7 @@ class Main : CoroutineScope by CoroutineScope(Dispatchers.Default + SupervisorJo this.config = ConfigManager() this.kubernetesClient = KubernetesClient() this.redisClient = RedisClient() + this.resourcePackManager = ResourcePackManager() manager = Manager(config.redisConfig.URI, config.redisConfig.PubSubPrefix) manager.subscribe(MESSAGE_TOPIC) @@ -113,14 +117,20 @@ class Main : CoroutineScope by CoroutineScope(Dispatchers.Default + SupervisorJo it.result = ServerPreConnectEvent.ServerResult.allowed(lobby) } + // Remove player on disconnect + proxy.eventManager.register(this, DisconnectEvent::class.java) { + this.resourcePackManager.removePlayer(it.player) + } + + // Update resourcepacks @Suppress("UnstableApiUsage") proxy.eventManager.register(this, ServerPostConnectEvent::class.java) { + // TODO: Get Galaxy Type if (it.player.currentServer.get().serverInfo.name == "galaxy-lobby") { - ResourcePackHelper.trySendResourcePack(it.player, "lobby") + this.resourcePackManager.updatePlayerResourcePacks(it.player, "lobby") } else { - // TODO: Check Galaxy Type if (it.previousServer?.serverInfo?.name != "galaxy-lobby") return@register - ResourcePackHelper.trySendResourcePack(it.player, "normal_galaxy") + this.resourcePackManager.updatePlayerResourcePacks(it.player, "normal_galaxy") } } diff --git a/src/main/kotlin/one/oktw/galaxy/proxy/config/ConfigManager.kt b/src/main/kotlin/one/oktw/galaxy/proxy/config/ConfigManager.kt index ee60616..330caf2 100644 --- a/src/main/kotlin/one/oktw/galaxy/proxy/config/ConfigManager.kt +++ b/src/main/kotlin/one/oktw/galaxy/proxy/config/ConfigManager.kt @@ -1,6 +1,7 @@ package one.oktw.galaxy.proxy.config import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import kotlinx.coroutines.runBlocking import one.oktw.galaxy.proxy.Main.Companion.main import one.oktw.galaxy.proxy.config.model.GalaxySpec @@ -22,10 +23,11 @@ class ConfigManager(private val basePath: Path = Paths.get("config")) { lateinit var redisConfig: RedisConfig private set val galaxies = HashMap() - val galaxiesResourcePack = ConcurrentHashMap() + val resourcePacks = ConcurrentHashMap() init { readConfig() + readResourcePacks() readGalaxies(FileSystems.newFileSystem(this::class.java.getResource("/config")!!.toURI(), emptyMap()).getPath("/config/galaxies")) readGalaxies(basePath.resolve("galaxies")) } @@ -41,6 +43,7 @@ class ConfigManager(private val basePath: Path = Paths.get("config")) { fun reloadGalaxies() { readGalaxies(basePath.resolve("galaxies")) + readResourcePacks() } private fun readConfig() { @@ -56,13 +59,22 @@ class ConfigManager(private val basePath: Path = Paths.get("config")) { Files.newBufferedReader(file).use { json -> val galaxyName = file.fileName.toString().substringBeforeLast(".") galaxies[galaxyName] = gson.fromJson(json, GalaxySpec::class.java) - runBlocking { - try { - galaxiesResourcePack[galaxyName] = galaxies[galaxyName]?.let { spec -> if (spec.ResourcePack.isNotBlank()) ResourcePack.new(spec.ResourcePack) else null } ?: return@runBlocking - } catch (e: Exception) { - main.logger.error("Resource pack load failed!", e) - } + } + } + } + } + + private fun readResourcePacks() { + val mapType = object : TypeToken>() {} + val packs = fallbackToResource("resource_packs.json").reader().use { gson.fromJson(it, mapType) } + packs.forEach { pack -> + runBlocking { + try { + if (pack.value.isNotEmpty()) { + resourcePacks[pack.key] = ResourcePack.new(pack.value) } + } catch (e: Exception) { + main.logger.error("Resource pack {} load failed!", pack.key, e) } } } diff --git a/src/main/kotlin/one/oktw/galaxy/proxy/config/model/GalaxySpec.kt b/src/main/kotlin/one/oktw/galaxy/proxy/config/model/GalaxySpec.kt index 15c3809..9629968 100644 --- a/src/main/kotlin/one/oktw/galaxy/proxy/config/model/GalaxySpec.kt +++ b/src/main/kotlin/one/oktw/galaxy/proxy/config/model/GalaxySpec.kt @@ -4,7 +4,7 @@ data class GalaxySpec( val Image: String, val PullSecret: String, val Type: GalaxyType, - val ResourcePack: String, + val ResourcePacks: Set, val Resource: GalaxyResource? = null, val Storage: GalaxyStorage? = null ) { diff --git a/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePack.kt b/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePack.kt index 637adf4..e55bead 100644 --- a/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePack.kt +++ b/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePack.kt @@ -19,8 +19,10 @@ package one.oktw.galaxy.proxy.resourcepack import com.google.common.hash.Hashing +import com.velocitypowered.api.proxy.player.ResourcePackInfo import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.withContext +import one.oktw.galaxy.proxy.Main.Companion.main import java.io.FileNotFoundException import java.io.IOException import java.net.URI @@ -32,13 +34,18 @@ class ResourcePack private constructor(url: String) { var uri = URI(url) private set - var hash:ByteArray + var hash: ByteArray private set init { this.hash = getHashFromUri(uri) } + fun packInfo(): ResourcePackInfo = main.proxy.createResourcePackBuilder(this.uri.toString()) + .setHash(this.hash) + .setShouldForce(true) + .build() + @Throws(FileNotFoundException::class) @Suppress("UnstableApiUsage", "DEPRECATION") private fun getHashFromUri(uri: URI): ByteArray { diff --git a/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePackHelper.kt b/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePackHelper.kt deleted file mode 100644 index 02c6744..0000000 --- a/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePackHelper.kt +++ /dev/null @@ -1,20 +0,0 @@ -package one.oktw.galaxy.proxy.resourcepack - -import com.velocitypowered.api.proxy.Player -import one.oktw.galaxy.proxy.Main.Companion.main - -class ResourcePackHelper { - companion object{ - fun trySendResourcePack(player: Player, galaxy: String){ - val resourcePack = main.config.galaxiesResourcePack[galaxy] ?: return - - player.clearResourcePacks() - player.sendResourcePackOffer( - main.proxy.createResourcePackBuilder(resourcePack.uri.toString()) - .setHash(resourcePack.hash) - .setShouldForce(true) - .build() - ) - } - } -} diff --git a/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePackManager.kt b/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePackManager.kt new file mode 100644 index 0000000..81a10bb --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/proxy/resourcepack/ResourcePackManager.kt @@ -0,0 +1,38 @@ +package one.oktw.galaxy.proxy.resourcepack + +import com.velocitypowered.api.proxy.Player +import com.velocitypowered.api.proxy.player.ResourcePackInfo +import one.oktw.galaxy.proxy.Main.Companion.main +import kotlin.math.min + +class ResourcePackManager { + private val appliedPacks: MutableMap> = mutableMapOf() + + fun updatePlayerResourcePacks(player: Player, galaxy: String) { + val new = main.config.galaxies[galaxy]?.ResourcePacks?.mapNotNull { main.config.resourcePacks[it]?.packInfo() } ?: emptyList() + val old = this.appliedPacks.getOrElse(player) { listOf() } + + // Matching new resource packs + var updateIndex = old.lastIndex + for (i in 0..min(old.size, new.size)) { + if (old.getOrNull(i)?.hash != new.getOrNull(i)?.hash) { + updateIndex = i + break + } + } + + // Remove not match resource packs + old.subList(updateIndex, old.size).forEach(player::removeResourcePacks) + + // Add new resource packs + new.subList(updateIndex, new.size).forEach(player::sendResourcePacks) + + // Save player resource packs state + appliedPacks[player] = new.toList() + } + + // Remove player resource packs state + fun removePlayer(player: Player) { + appliedPacks.remove(player) + } +} diff --git a/src/main/resources/config/galaxies/lobby.json b/src/main/resources/config/galaxies/lobby.json index d5a212f..69c9697 100644 --- a/src/main/resources/config/galaxies/lobby.json +++ b/src/main/resources/config/galaxies/lobby.json @@ -2,7 +2,7 @@ "Image": "registry.gitlab.com/oktw-network/galaxy", "PullSecret": "", "Type": "LOBBY", - "ResourcePack": "", + "ResourcePacks": ["base", "lobby"], "Resource": { "CPULimit": "4000m", "CPURequest": "300m", diff --git a/src/main/resources/config/galaxies/normal_galaxy.json b/src/main/resources/config/galaxies/normal_galaxy.json index c729769..c540adf 100644 --- a/src/main/resources/config/galaxies/normal_galaxy.json +++ b/src/main/resources/config/galaxies/normal_galaxy.json @@ -2,7 +2,7 @@ "Image": "registry.gitlab.com/oktw-network/galaxy", "PullSecret": "", "Type": "GALAXY", - "ResourcePack": "", + "ResourcePacks": ["base"], "Resource": { "CPULimit": "4000m", "CPURequest": "300m", diff --git a/src/main/resources/config/resource_packs.json b/src/main/resources/config/resource_packs.json new file mode 100644 index 0000000..e5d93aa --- /dev/null +++ b/src/main/resources/config/resource_packs.json @@ -0,0 +1,4 @@ +{ + "base": "", + "lobby": "" +}