mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 11:24:56 -04:00
wip assets manager (2)
This commit is contained in:
parent
b5d67855c0
commit
e929d80cae
@ -22,6 +22,7 @@ import de.bixilon.minosoft.data.language.LanguageManager.Companion.load
|
||||
import de.bixilon.minosoft.data.language.MultiLanguageManager
|
||||
import de.bixilon.minosoft.data.registries.DefaultRegistries
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.registries.versions.Versions
|
||||
import de.bixilon.minosoft.gui.eros.Eros
|
||||
import de.bixilon.minosoft.gui.eros.XStartOnFirstThreadWarning
|
||||
import de.bixilon.minosoft.gui.eros.crash.ErosCrashReport.Companion.crash
|
||||
@ -69,7 +70,7 @@ object Minosoft {
|
||||
|
||||
taskWorker += Task(identifier = StartupTasks.LOAD_VERSIONS, priority = ThreadPool.HIGH, executor = {
|
||||
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Loading versions..." }
|
||||
// Versions.loadAvailableVersions(MINOSOFT_ASSETS_MANAGER.readLegacyJsonAsset(ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "mapping/versions.json")))
|
||||
Versions.load()
|
||||
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Versions loaded!" }
|
||||
})
|
||||
|
||||
@ -90,7 +91,7 @@ object Minosoft {
|
||||
val language = ErosProfileManager.selected.general.language
|
||||
ErosProfileManager.selected.general::language.profileWatch(this, true) {
|
||||
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Loading language files (${language})" }
|
||||
LANGUAGE_MANAGER.translators[ProtocolDefinition.MINOSOFT_NAMESPACE] = load(it, null, ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "language/"))
|
||||
LANGUAGE_MANAGER.translators[ProtocolDefinition.MINOSOFT_NAMESPACE] = load(it, null, MINOSOFT_ASSETS_MANAGER, ResourceLocation(ProtocolDefinition.MINOSOFT_NAMESPACE, "language/"))
|
||||
Log.log(LogMessageType.OTHER, LogLevels.VERBOSE) { "Language files loaded!" }
|
||||
}
|
||||
})
|
||||
|
31
src/main/java/de/bixilon/minosoft/assets/AssetsLoader.kt
Normal file
31
src/main/java/de/bixilon/minosoft/assets/AssetsLoader.kt
Normal file
@ -0,0 +1,31 @@
|
||||
package de.bixilon.minosoft.assets
|
||||
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.assets.minecraft.JarAssetsManager
|
||||
import de.bixilon.minosoft.assets.minecraft.index.IndexAssetsManager
|
||||
import de.bixilon.minosoft.assets.multi.PriorityAssetsManager
|
||||
import de.bixilon.minosoft.assets.properties.version.AssetsVersionProperties
|
||||
import de.bixilon.minosoft.assets.properties.version.AssetsVersionProperty
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfile
|
||||
import de.bixilon.minosoft.data.registries.versions.Version
|
||||
|
||||
object AssetsLoader {
|
||||
|
||||
fun create(profile: ResourcesProfile, version: Version, property: AssetsVersionProperty = AssetsVersionProperties[version] ?: throw IllegalAccessException("$version has no assets!")): AssetsManager {
|
||||
val assetsManager = PriorityAssetsManager()
|
||||
|
||||
for (resourcePack in profile.assets.resourcePacks) {
|
||||
assetsManager += resourcePack.type.creator(resourcePack)
|
||||
}
|
||||
|
||||
if (!profile.assets.disableIndexAssets) {
|
||||
assetsManager += IndexAssetsManager(profile, property.indexVersion, property.indexHash, profile.assets.indexAssetsTypes.toSet())
|
||||
}
|
||||
if (!profile.assets.disableJarAssets) {
|
||||
assetsManager += JarAssetsManager(property.jarAssetsHash, property.clientJarHash, profile, version)
|
||||
}
|
||||
assetsManager += Minosoft.MINOSOFT_ASSETS_MANAGER
|
||||
|
||||
return assetsManager
|
||||
}
|
||||
}
|
@ -11,11 +11,15 @@
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.assets.file
|
||||
package de.bixilon.minosoft.assets.directory
|
||||
|
||||
import de.bixilon.minosoft.assets.AssetsManager
|
||||
import de.bixilon.minosoft.assets.util.FileAssetsUtil.toAssetName
|
||||
import de.bixilon.minosoft.assets.util.FileUtil
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.util.CountUpAndDownLatch
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.InputStream
|
||||
|
||||
|
||||
@ -25,18 +29,50 @@ import java.io.InputStream
|
||||
|
||||
class DirectoryAssetsManager(
|
||||
private val basePath: String,
|
||||
) : FileAssetsManager() {
|
||||
) : AssetsManager {
|
||||
override val namespaces: MutableSet<String> = mutableSetOf()
|
||||
private var assets: MutableSet<ResourceLocation> = mutableSetOf()
|
||||
|
||||
private val ResourceLocation.filePath: String
|
||||
get() = "$basePath/$namespace/$path"
|
||||
|
||||
override fun load(latch: CountUpAndDownLatch) = Unit
|
||||
// ToDo: Load properties
|
||||
|
||||
private fun scanDirectory(directory: File) {
|
||||
for (file in directory.listFiles() ?: return) {
|
||||
if (file.isDirectory) {
|
||||
scanDirectory(file)
|
||||
continue
|
||||
}
|
||||
val path = file.path.removePrefix(basePath).removePrefix("/").toAssetName(false) ?: continue
|
||||
assets += path
|
||||
namespaces += path.namespace
|
||||
}
|
||||
}
|
||||
|
||||
override fun load(latch: CountUpAndDownLatch) {
|
||||
scanDirectory(File(basePath))
|
||||
}
|
||||
|
||||
override fun unload() {
|
||||
assets.clear()
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<Map.Entry<ResourceLocation, ByteArray>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun get(path: ResourceLocation): InputStream {
|
||||
if (path !in assets) {
|
||||
throw FileNotFoundException("Can not find asset $path")
|
||||
}
|
||||
return FileUtil.readFile(path.filePath, false)
|
||||
}
|
||||
|
||||
override fun nullGet(path: ResourceLocation): InputStream? {
|
||||
if (path !in assets) {
|
||||
return null
|
||||
}
|
||||
return FileUtil.saveReadFile(path.filePath, false)
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package de.bixilon.minosoft.assets.file
|
||||
|
||||
import de.bixilon.minosoft.assets.AssetsManager
|
||||
import de.bixilon.minosoft.assets.directory.DirectoryAssetsManager
|
||||
import java.io.FileNotFoundException
|
||||
import java.net.URLDecoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
@ -41,12 +41,15 @@ class JarAssetsManager(
|
||||
val version: Version,
|
||||
) : MinecraftAssetsManager {
|
||||
override val namespaces = setOf(ProtocolDefinition.DEFAULT_NAMESPACE)
|
||||
private var jarAssets: Map<String, ByteArray> = mapOf()
|
||||
private var jarAssets: MutableMap<String, ByteArray> = mutableMapOf()
|
||||
|
||||
override fun load(latch: CountUpAndDownLatch) {
|
||||
val jarAssetFile = File(FileAssetsUtil.getPath(jarAssetsHash))
|
||||
if (FileAssetsUtil.verifyAsset(jarAssetsHash, jarAssetFile, profile.verify)) {
|
||||
jarAssets = FileUtil.readFile(jarAssetFile).readArchive()
|
||||
val jarAssets = FileUtil.readFile(jarAssetFile).readArchive()
|
||||
for ((path, data) in jarAssets) {
|
||||
this.jarAssets[path.removePrefix("assets/" + ProtocolDefinition.DEFAULT_NAMESPACE + "/")] = data
|
||||
}
|
||||
} else {
|
||||
var clientJar = FileUtil.saveReadFile(File(FileAssetsUtil.getPath(clientJarHash)), false)?.readZipArchive()
|
||||
if (clientJar == null) {
|
||||
@ -112,7 +115,7 @@ class JarAssetsManager(
|
||||
}
|
||||
|
||||
override fun unload() {
|
||||
jarAssets = mapOf()
|
||||
jarAssets = mutableMapOf()
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<Map.Entry<ResourceLocation, ByteArray>> {
|
||||
|
@ -20,11 +20,15 @@ import de.bixilon.minosoft.assets.util.FileUtil
|
||||
import de.bixilon.minosoft.assets.util.FileUtil.readJsonObject
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfile
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.CountUpAndDownLatch
|
||||
import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
|
||||
import de.bixilon.minosoft.util.KUtil.toLong
|
||||
import de.bixilon.minosoft.util.Util
|
||||
import de.bixilon.minosoft.util.json.Jackson
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
import de.bixilon.minosoft.util.logging.LogLevels
|
||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||
import de.bixilon.minosoft.util.task.pool.DefaultThreadPool
|
||||
import de.bixilon.minosoft.util.task.pool.ThreadPool
|
||||
@ -39,13 +43,13 @@ import java.io.InputStream
|
||||
*/
|
||||
class IndexAssetsManager(
|
||||
private val profile: ResourcesProfile,
|
||||
private val verify: Boolean,
|
||||
private val assetsVersion: String,
|
||||
private val indexHash: String,
|
||||
private val types: Set<IndexAssetsType>,
|
||||
) : MinecraftAssetsManager {
|
||||
private val verify: Boolean = profile.verify
|
||||
private val assets: MutableMap<ResourceLocation, AssetsProperty> = synchronizedMapOf()
|
||||
override val namespaces: MutableSet<String> = mutableSetOf()
|
||||
override val namespaces: Set<String> = setOf(ProtocolDefinition.DEFAULT_NAMESPACE)
|
||||
|
||||
private fun downloadAssetsIndex(): Map<String, Any> {
|
||||
return Jackson.MAPPER.readValue(FileAssetsUtil.downloadAndGetAsset(Util.formatString(profile.source.mojangPackages,
|
||||
@ -65,6 +69,7 @@ class IndexAssetsManager(
|
||||
"hashPrefix" to hash.substring(0, 2),
|
||||
"fullHash" to hash,
|
||||
))
|
||||
Log.log(LogMessageType.ASSETS, LogLevels.VERBOSE) { "Downloading asset $url" }
|
||||
val downloadedHash = FileAssetsUtil.downloadAsset(url)
|
||||
if (downloadedHash != hash) {
|
||||
throw IOException("Verification of asset $hash failed!")
|
||||
@ -73,23 +78,34 @@ class IndexAssetsManager(
|
||||
|
||||
override fun load(latch: CountUpAndDownLatch) {
|
||||
var assets = FileUtil.saveReadFile(FileAssetsUtil.getPath(indexHash))?.readJsonObject() ?: downloadAssetsIndex()
|
||||
|
||||
assets["objects"].let { assets = it.asCompound() }
|
||||
val tasks = CountUpAndDownLatch(0)
|
||||
val assetsLatch = CountUpAndDownLatch(assets.size, parent = latch)
|
||||
|
||||
val tasks = CountUpAndDownLatch(0)
|
||||
assets["objects"].let { assets = it.asCompound() }
|
||||
for ((path, data) in assets) {
|
||||
check(data is Map<*, *>)
|
||||
val name = path.toAssetName() ?: continue
|
||||
val name = path.toAssetName(false)
|
||||
if (name == null) {
|
||||
assetsLatch.dec()
|
||||
continue
|
||||
}
|
||||
|
||||
val type = when {
|
||||
name.path.startsWith("lang/") -> IndexAssetsType.LANGUAGE
|
||||
name.path.startsWith("sounds/") -> IndexAssetsType.SOUNDS
|
||||
name.path == "sounds.json" -> IndexAssetsType.SOUNDS
|
||||
name.path.startsWith("textures/") -> IndexAssetsType.TEXTURES
|
||||
else -> continue
|
||||
else -> {
|
||||
assetsLatch.dec()
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (type !in this.types) {
|
||||
assetsLatch.dec()
|
||||
continue
|
||||
}
|
||||
namespaces += name.namespace
|
||||
|
||||
val size = data["size"]?.toLong() ?: -1
|
||||
val hash = data["hash"].toString()
|
||||
if (tasks.count > DefaultThreadPool.threadCount - 1) {
|
||||
|
@ -1,8 +1,17 @@
|
||||
package de.bixilon.minosoft.assets.minecraft.index
|
||||
|
||||
import de.bixilon.minosoft.util.KUtil
|
||||
import de.bixilon.minosoft.util.enum.ValuesEnum
|
||||
|
||||
enum class IndexAssetsType {
|
||||
LANGUAGE,
|
||||
SOUNDS,
|
||||
TEXTURES,
|
||||
;
|
||||
|
||||
companion object : ValuesEnum<IndexAssetsType> {
|
||||
override val VALUES: Array<IndexAssetsType> = values()
|
||||
override val NAME_MAP: Map<String, IndexAssetsType> = KUtil.getEnumValues(VALUES)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -46,9 +46,12 @@ class PriorityAssetsManager(
|
||||
fun add(manager: AssetsManager) {
|
||||
for (namespace in manager.namespaces) {
|
||||
this.managers.getOrPut(namespace) { mutableSetOf() } += manager
|
||||
this.namespaces += namespace
|
||||
}
|
||||
}
|
||||
|
||||
operator fun plusAssign(manager: AssetsManager) = add(manager)
|
||||
|
||||
override fun get(path: ResourceLocation): InputStream {
|
||||
return nullGet(path) ?: throw FileNotFoundException("Can not find assets-manager for $path")
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ object AssetsVersionProperties {
|
||||
}
|
||||
val assetsProperties: Map<String, AssetsVersionProperty> = Minosoft.MINOSOFT_ASSETS_MANAGER[ASSETS_PROPERTIES_FILE].readJson()
|
||||
for ((versionName, property) in assetsProperties) {
|
||||
PROPERTIES[Versions.getVersionByName(versionName) ?: continue] = property
|
||||
PROPERTIES[Versions[versionName] ?: continue] = property
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,7 @@ object FileAssetsUtil {
|
||||
file.parentFile.apply {
|
||||
mkdirs()
|
||||
if (!isDirectory) {
|
||||
tempFile.delete()
|
||||
throw IllegalStateException("Could not create folder $this")
|
||||
}
|
||||
}
|
||||
@ -108,8 +109,8 @@ object FileAssetsUtil {
|
||||
return saveAndGet(ByteArrayInputStream(data), compress, false)
|
||||
}
|
||||
|
||||
fun String.toAssetName(): ResourceLocation? {
|
||||
if (!startsWith("assets/")) {
|
||||
fun String.toAssetName(verifyPrefix: Boolean = true): ResourceLocation? {
|
||||
if (verifyPrefix && !startsWith("assets/")) {
|
||||
return null
|
||||
}
|
||||
val split = removePrefix("assets/").split("/", limit = 2)
|
||||
@ -135,26 +136,31 @@ object FileAssetsUtil {
|
||||
return true
|
||||
}
|
||||
|
||||
val digest = MessageDigest.getInstance("SHA-1")
|
||||
try {
|
||||
val digest = MessageDigest.getInstance("SHA-1")
|
||||
|
||||
var input: InputStream = FileInputStream(file)
|
||||
if (compress) {
|
||||
input = ZstdInputStream(input)
|
||||
}
|
||||
|
||||
val buffer = ByteArray(ProtocolDefinition.DEFAULT_BUFFER_SIZE)
|
||||
var length: Int
|
||||
while (true) {
|
||||
length = input.read(buffer, 0, buffer.size)
|
||||
if (length < 0) {
|
||||
break
|
||||
var input: InputStream = FileInputStream(file)
|
||||
if (compress) {
|
||||
input = ZstdInputStream(input)
|
||||
}
|
||||
digest.update(buffer, 0, length)
|
||||
}
|
||||
val equals = hash != Util.byteArrayToHexString(digest.digest())
|
||||
if (!equals) {
|
||||
|
||||
val buffer = ByteArray(ProtocolDefinition.DEFAULT_BUFFER_SIZE)
|
||||
var length: Int
|
||||
while (true) {
|
||||
length = input.read(buffer, 0, buffer.size)
|
||||
if (length < 0) {
|
||||
break
|
||||
}
|
||||
digest.update(buffer, 0, length)
|
||||
}
|
||||
val equals = hash == Util.byteArrayToHexString(digest.digest())
|
||||
if (!equals) {
|
||||
file.delete()
|
||||
}
|
||||
return equals
|
||||
} catch (exception: Throwable) {
|
||||
file.delete()
|
||||
return false
|
||||
}
|
||||
return equals
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,9 @@ package de.bixilon.minosoft.assets.util
|
||||
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.github.luben.zstd.ZstdInputStream
|
||||
import de.bixilon.mbf.MBFBinaryReader
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
import de.bixilon.minosoft.util.json.Jackson
|
||||
import de.matthiasmann.twl.utils.PNGDecoder
|
||||
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream
|
||||
@ -127,4 +129,8 @@ object FileUtil {
|
||||
|
||||
return colors
|
||||
}
|
||||
|
||||
fun InputStream.readMBFMap(): Map<Any, Any> {
|
||||
return MBFBinaryReader(this).readMBF().data.unsafeCast()
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import de.bixilon.minosoft.config.profile.profiles.account.AccountProfile
|
||||
import de.bixilon.minosoft.config.profile.profiles.account.AccountProfileManager
|
||||
import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager.delegate
|
||||
import de.bixilon.minosoft.config.profile.profiles.eros.ErosProfileManager.mapDelegate
|
||||
import de.bixilon.minosoft.data.language.LanguageManager
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.util.KUtil.fullName
|
||||
import java.util.*
|
||||
@ -14,7 +15,7 @@ class GeneralC {
|
||||
/**
|
||||
* Language to use for eros. This is also the fallback language for other profiles
|
||||
*/
|
||||
var language: String by delegate(Locale.getDefault()?.fullName ?: "en_US")
|
||||
var language: String by delegate(Locale.getDefault()?.fullName ?: LanguageManager.FALLBACK_LANGUAGE)
|
||||
|
||||
@get:JsonProperty("account_profile") private var _accountProfile: String? by delegate(null)
|
||||
|
||||
@ -29,5 +30,4 @@ class GeneralC {
|
||||
* If profile is not set or not found, the global default profile is used
|
||||
*/
|
||||
var profileOverrides: MutableMap<ResourceLocation, String> by mapDelegate()
|
||||
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ class Server(
|
||||
private var _forcedVersion by delegate(forcedVersion?.name)
|
||||
|
||||
@get:JsonIgnore
|
||||
var forcedVersion by backingDelegate(getter = { Versions.getVersionByName(_forcedVersion) }, setter = { _forcedVersion = it?.name })
|
||||
var forcedVersion by backingDelegate(getter = { Versions[_forcedVersion] }, setter = { _forcedVersion = it?.name })
|
||||
|
||||
@get:JsonInclude(JsonInclude.Include.NON_DEFAULT)
|
||||
var faviconHash: String? by delegate(null) { if (it != null) check(it.length == 40) { "Not a valid sha1 hash!" } }
|
||||
|
@ -4,6 +4,7 @@ import de.bixilon.minosoft.config.profile.ProfileManager
|
||||
import de.bixilon.minosoft.config.profile.profiles.Profile
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfileManager.delegate
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfileManager.latestVersion
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.assets.AssetsC
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.source.SourceC
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
|
||||
@ -23,6 +24,7 @@ class ResourcesProfile(
|
||||
override var description by delegate(description ?: "")
|
||||
|
||||
val source = SourceC()
|
||||
val assets = AssetsC()
|
||||
|
||||
/**
|
||||
* If set, all downloaded assets will be checked on load.
|
||||
|
@ -0,0 +1,15 @@
|
||||
package de.bixilon.minosoft.config.profile.profiles.resources.assets
|
||||
|
||||
import de.bixilon.minosoft.assets.minecraft.index.IndexAssetsType
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfileManager.delegate
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfileManager.listDelegate
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfileManager.setDelegate
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.assets.packs.ResourcePack
|
||||
|
||||
class AssetsC {
|
||||
var disableJarAssets by delegate(false)
|
||||
var disableIndexAssets by delegate(false)
|
||||
val indexAssetsTypes: MutableSet<IndexAssetsType> by setDelegate(mutableSetOf(*IndexAssetsType.VALUES))
|
||||
|
||||
val resourcePacks: List<ResourcePack> by listDelegate()
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package de.bixilon.minosoft.config.profile.profiles.resources.assets.packs
|
||||
|
||||
class ResourcePack(
|
||||
var type: ResourcePackType,
|
||||
var path: String,
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
package de.bixilon.minosoft.config.profile.profiles.resources.assets.packs
|
||||
|
||||
import de.bixilon.minosoft.assets.AssetsManager
|
||||
import de.bixilon.minosoft.assets.directory.DirectoryAssetsManager
|
||||
import de.bixilon.minosoft.assets.file.ZipAssetsManager
|
||||
|
||||
enum class ResourcePackType(val creator: (ResourcePack) -> AssetsManager) {
|
||||
ZIP({ ZipAssetsManager(it.path) }),
|
||||
DIRECTORY({ DirectoryAssetsManager(it.path) }),
|
||||
;
|
||||
}
|
@ -35,7 +35,7 @@ public class VersionParser extends CommandParser {
|
||||
if (StringUtils.isBlank(rawVersionName)) {
|
||||
throw new BlankStringCommandParseException(stringReader, rawVersionName);
|
||||
}
|
||||
Version version = Versions.getVersionByName(rawVersionName);
|
||||
Version version = Versions.INSTANCE.get(rawVersionName);
|
||||
if (version == null) {
|
||||
throw new InvalidVersionCommandParseException(stringReader, rawVersionName);
|
||||
}
|
||||
|
@ -254,20 +254,20 @@ class ItemStack(
|
||||
val enchantmentList: MutableList<Map<String, Any>> = mutableListOf()
|
||||
for ((enchantment, level) in enchantments) {
|
||||
val enchantmentTag: MutableMap<String, Any> = mutableMapOf()
|
||||
enchantmentTag[ENCHANTMENT_ID_TAG] = if (connection.version.isFlattened()) {
|
||||
enchantmentTag[ENCHANTMENT_ID_TAG] = if (connection.version.flattened) {
|
||||
enchantment.resourceLocation.full
|
||||
} else {
|
||||
connection.registries.enchantmentRegistry.getId(enchantment)
|
||||
}
|
||||
|
||||
enchantmentTag[ENCHANTMENT_LEVEL_TAG] = if (connection.version.isFlattened()) {
|
||||
enchantmentTag[ENCHANTMENT_LEVEL_TAG] = if (connection.version.flattened) {
|
||||
level
|
||||
} else {
|
||||
level.toShort()
|
||||
}
|
||||
enchantmentList += enchantmentTag
|
||||
}
|
||||
if (connection.version.isFlattened()) {
|
||||
if (connection.version.flattened) {
|
||||
nbt[ENCHANTMENT_FLATTENING_TAG] = enchantmentList
|
||||
} else {
|
||||
nbt[ENCHANTMENT_PRE_FLATTENING_TAG] = enchantmentList
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
package de.bixilon.minosoft.data.language
|
||||
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.assets.AssetsManager
|
||||
import de.bixilon.minosoft.assets.util.FileUtil.readAsString
|
||||
import de.bixilon.minosoft.assets.util.FileUtil.readJsonObject
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
@ -53,10 +53,9 @@ class LanguageManager(
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val FALLBACK_LANGUAGE = "en_US"
|
||||
|
||||
|
||||
fun load(language: String, version: Version?, path: ResourceLocation = ResourceLocation("lang/")): LanguageManager {
|
||||
val assetsManager = version?.jarAssetsManager ?: Minosoft.MINOSOFT_ASSETS_MANAGER
|
||||
fun load(language: String, version: Version?, assetsManager: AssetsManager, path: ResourceLocation = ResourceLocation("lang/")): LanguageManager {
|
||||
|
||||
fun loadMinecraftLanguage(language: String): Language {
|
||||
val data: MutableMap<ResourceLocation, String> = mutableMapOf()
|
||||
@ -82,13 +81,12 @@ class LanguageManager(
|
||||
|
||||
val languages: MutableList<Language> = mutableListOf()
|
||||
|
||||
if (language != "en_US") {
|
||||
if (language != FALLBACK_LANGUAGE) {
|
||||
tryCatch(FileNotFoundException::class.java, executor = { languages += loadMinecraftLanguage(language) })
|
||||
}
|
||||
languages += loadMinecraftLanguage("en_US")
|
||||
languages += loadMinecraftLanguage(FALLBACK_LANGUAGE)
|
||||
|
||||
return LanguageManager(languages)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
package de.bixilon.minosoft.data.registries
|
||||
|
||||
class RegistriesLoadingException : Exception {
|
||||
constructor()
|
||||
constructor(message: String?) : super(message)
|
||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
constructor(cause: Throwable?) : super(cause)
|
||||
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(message, cause, enableSuppression, writableStackTrace)
|
||||
}
|
@ -127,8 +127,8 @@ class Registries {
|
||||
}
|
||||
}
|
||||
|
||||
fun load(version: Version, pixlyzerData: MutableMap<String, Any>) {
|
||||
isFlattened = version.isFlattened()
|
||||
fun load(version: Version, pixlyzerData: Map<String, Any>) {
|
||||
isFlattened = version.flattened
|
||||
blockStateRegistry.flattened = isFlattened
|
||||
// pre init stuff
|
||||
loadShapes(pixlyzerData["shapes"]?.compoundCast())
|
||||
@ -157,7 +157,7 @@ class Registries {
|
||||
|
||||
entityTypeRegistry.rawInitialize(pixlyzerData["entities"]?.compoundCast(), this, EntityType)
|
||||
|
||||
motiveRegistry.rawInitialize(pixlyzerData["motives"]?.compoundCast(), this, Motive, version.isFlattened())
|
||||
motiveRegistry.rawInitialize(pixlyzerData["motives"]?.compoundCast(), this, Motive, version.flattened)
|
||||
soundEventRegistry.rawInitialize(pixlyzerData["sound_events"]?.compoundCast())
|
||||
particleTypeRegistry.rawInitialize(pixlyzerData["particles"]?.compoundCast(), this, ParticleType)
|
||||
materialRegistry.rawInitialize(pixlyzerData["materials"]?.compoundCast(), this, Material)
|
||||
@ -166,8 +166,8 @@ class Registries {
|
||||
biomeRegistry.rawInitialize(pixlyzerData["biomes"]?.compoundCast(), this, Biome)
|
||||
dimensionRegistry.rawInitialize(pixlyzerData["dimensions"]?.compoundCast(), this, Dimension)
|
||||
fluidRegistry.rawInitialize(pixlyzerData["fluids"]?.compoundCast(), this, Fluid)
|
||||
blockRegistry.rawInitialize(pixlyzerData["blocks"]?.compoundCast(), this, Block, version.isFlattened(), Registry.MetaTypes.BITS_4)
|
||||
itemRegistry.rawInitialize(pixlyzerData["items"]?.compoundCast(), this, Item, version.isFlattened(), Registry.MetaTypes.BITS_16)
|
||||
blockRegistry.rawInitialize(pixlyzerData["blocks"]?.compoundCast(), this, Block, version.flattened, Registry.MetaTypes.BITS_4)
|
||||
itemRegistry.rawInitialize(pixlyzerData["items"]?.compoundCast(), this, Item, version.flattened, Registry.MetaTypes.BITS_16)
|
||||
|
||||
blockEntityTypeRegistry.rawInitialize(pixlyzerData["block_entities"]?.compoundCast(), this, BlockEntityType)
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
package de.bixilon.minosoft.data.registries.registries
|
||||
|
||||
import de.bixilon.minosoft.assets.properties.version.AssetsVersionProperties
|
||||
import de.bixilon.minosoft.assets.util.FileAssetsUtil
|
||||
import de.bixilon.minosoft.assets.util.FileUtil
|
||||
import de.bixilon.minosoft.assets.util.FileUtil.readMBFMap
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfile
|
||||
import de.bixilon.minosoft.data.registries.versions.Version
|
||||
import de.bixilon.minosoft.util.Util
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
|
||||
object RegistriesLoader {
|
||||
|
||||
fun load(profile: ResourcesProfile, version: Version): Registries {
|
||||
// ToDo: Pre flattening support
|
||||
val pixlyzerHash = AssetsVersionProperties[version]?.pixlyzerHash ?: throw IllegalStateException("$version has no pixlyzer data available!")
|
||||
|
||||
val pixlyzerData = getPixlyzerData(profile.source.pixlyzer, pixlyzerHash)
|
||||
|
||||
val registries = Registries()
|
||||
registries.load(version, pixlyzerData)
|
||||
|
||||
return registries
|
||||
}
|
||||
|
||||
private fun getPixlyzerData(url: String, hash: String): Map<String, Any> {
|
||||
val path = FileAssetsUtil.getPath(hash)
|
||||
val file = File(path)
|
||||
if (file.exists()) {
|
||||
// ToDo: Verify
|
||||
return FileUtil.readFile(file, false).readMBFMap().compoundCast() ?: throw IllegalStateException("Could not read pixlyzer data!")
|
||||
}
|
||||
|
||||
val savedHash = FileAssetsUtil.downloadAndGetAsset(Util.formatString(
|
||||
url,
|
||||
mapOf(
|
||||
"hashPrefix" to hash.substring(0, 2),
|
||||
"fullHash" to hash,
|
||||
)
|
||||
), false)
|
||||
if (savedHash.first != hash) {
|
||||
throw IllegalStateException("Data mismatch, expected $hash, got ${savedHash.first}")
|
||||
}
|
||||
|
||||
return ByteArrayInputStream(savedHash.second).readMBFMap().compoundCast() ?: throw IllegalStateException("Invalid pixlyzer data!")
|
||||
}
|
||||
}
|
@ -1,157 +1,45 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
package de.bixilon.minosoft.data.registries.versions
|
||||
|
||||
import com.google.common.collect.HashBiMap
|
||||
import de.bixilon.mbf.MBFBinaryReader
|
||||
import de.bixilon.minosoft.assets.minecraft.JarAssetsManager
|
||||
import de.bixilon.minosoft.assets.minecraft.index.IndexAssetsManager
|
||||
import de.bixilon.minosoft.assets.properties.version.AssetsVersionProperties
|
||||
import de.bixilon.minosoft.assets.util.FileAssetsUtil
|
||||
import de.bixilon.minosoft.assets.util.FileUtil
|
||||
import de.bixilon.minosoft.config.profile.profiles.resources.ResourcesProfile
|
||||
import de.bixilon.minosoft.data.registries.registries.Registries
|
||||
import de.bixilon.minosoft.protocol.protocol.PacketTypes.C2S
|
||||
import de.bixilon.minosoft.protocol.protocol.PacketTypes.S2C
|
||||
import de.bixilon.minosoft.data.registries.registries.RegistriesLoader
|
||||
import de.bixilon.minosoft.protocol.protocol.PacketTypes
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolStates
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.V_15W31A
|
||||
import de.bixilon.minosoft.util.CountUpAndDownLatch
|
||||
import de.bixilon.minosoft.util.KUtil
|
||||
import de.bixilon.minosoft.util.KUtil.decide
|
||||
import de.bixilon.minosoft.util.logging.Log
|
||||
import de.bixilon.minosoft.util.logging.LogLevels
|
||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||
|
||||
@Deprecated(message = "Some refactoring needed")
|
||||
data class Version(
|
||||
var name: String,
|
||||
class Version(
|
||||
val name: String,
|
||||
val versionId: Int,
|
||||
val protocolId: Int,
|
||||
val c2SPacketMapping: Map<ProtocolStates, HashBiMap<C2S, Int>>,
|
||||
val s2CPacketMapping: Map<ProtocolStates, HashBiMap<S2C, Int>>,
|
||||
val s2cPackets: Map<ProtocolStates, Array<PacketTypes.S2C>>,
|
||||
val c2sPackets: Map<ProtocolStates, Array<PacketTypes.C2S>>,
|
||||
) {
|
||||
val sortingId: Int = (versionId == -1).decide(Int.MAX_VALUE, versionId)
|
||||
val type: VersionTypes = VersionTypes[this]
|
||||
var isLoaded = false
|
||||
val registries: Registries = Registries()
|
||||
lateinit var jarAssetsManager: JarAssetsManager
|
||||
lateinit var indexAssetsManager: IndexAssetsManager
|
||||
val type = VersionTypes[this]
|
||||
var registries: Registries? = null
|
||||
private set
|
||||
|
||||
fun getPacketById(state: ProtocolStates, command: Int): S2C? {
|
||||
return s2CPacketMapping[state]?.inverse()?.get(command)
|
||||
}
|
||||
|
||||
fun getPacketId(packet: C2S): Int? {
|
||||
return c2SPacketMapping[packet.state]?.get(packet)
|
||||
}
|
||||
|
||||
fun isFlattened(): Boolean {
|
||||
return versionId >= ProtocolDefinition.FLATTING_VERSION_ID
|
||||
}
|
||||
|
||||
private fun initializeAssetManger(latch: CountUpAndDownLatch) {
|
||||
if (this::jarAssetsManager.isInitialized) {
|
||||
@Synchronized
|
||||
fun load(profile: ResourcesProfile) {
|
||||
if (registries != null) {
|
||||
// already loaded
|
||||
return
|
||||
}
|
||||
if (!isFlattened() && versionId != ProtocolDefinition.PRE_FLATTENING_VERSION_ID) {
|
||||
jarAssetsManager = Versions.PRE_FLATTENING_VERSION.jarAssetsManager
|
||||
return
|
||||
}
|
||||
// ToDo
|
||||
registries = RegistriesLoader.load(profile, this)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun load(latch: CountUpAndDownLatch) {
|
||||
if (isLoaded) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isFlattened() && this !== Versions.PRE_FLATTENING_VERSION && !Versions.PRE_FLATTENING_VERSION.isLoaded) {
|
||||
// no matter what, we need the version mapping for all pre flattening versions
|
||||
try {
|
||||
Versions.PRE_FLATTENING_VERSION.load(latch)
|
||||
} catch (exception: Exception) {
|
||||
Versions.PRE_FLATTENING_VERSION.unload()
|
||||
Versions.PRE_FLATTENING_MAPPING = null
|
||||
throw exception
|
||||
}
|
||||
}
|
||||
latch.inc()
|
||||
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.INFO) { "Loading registries for $this..." }
|
||||
initializeAssetManger(latch)
|
||||
val startTime = KUtil.time
|
||||
|
||||
|
||||
if (versionId == ProtocolDefinition.PRE_FLATTENING_VERSION_ID) {
|
||||
Versions.PRE_FLATTENING_MAPPING = registries
|
||||
} else if (!isFlattened()) {
|
||||
registries.parentRegistries = Versions.PRE_FLATTENING_MAPPING
|
||||
}
|
||||
val pixlyzerData = try {
|
||||
MBFBinaryReader(FileUtil.readFile(FileAssetsUtil.getPath(AssetsVersionProperties[this]!!.pixlyzerHash ?: throw IllegalStateException("$this has no pixlyzer data!")), false)).readMBF().data.asCompound()
|
||||
} catch (exception: Throwable) {
|
||||
// should not happen, but if this version is not flattened, we can fallback to the flatten mappings. Some things might not work...
|
||||
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.VERBOSE) { exception }
|
||||
if (isFlattened()) {
|
||||
throw exception
|
||||
}
|
||||
if (versionId == ProtocolDefinition.PRE_FLATTENING_VERSION_ID) {
|
||||
Versions.PRE_FLATTENING_MAPPING = null
|
||||
}
|
||||
mutableMapOf()
|
||||
}
|
||||
latch.inc()
|
||||
registries.load(this, pixlyzerData)
|
||||
latch.dec()
|
||||
if (pixlyzerData.isNotEmpty()) {
|
||||
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.INFO) { "Loaded registries for $name in ${KUtil.time - startTime}ms" }
|
||||
} else {
|
||||
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.WARN) { "Could not load registries for ${name}. Some features might not work." }
|
||||
}
|
||||
isLoaded = true
|
||||
latch.dec()
|
||||
}
|
||||
|
||||
fun unload() {
|
||||
registries.clear()
|
||||
if (registries.parentRegistries == registries) {
|
||||
registries.parentRegistries = null
|
||||
}
|
||||
isLoaded = false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return versionId
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (super.equals(other)) {
|
||||
return true
|
||||
}
|
||||
if (other !is Version) {
|
||||
return false
|
||||
}
|
||||
return if (hashCode() != other.hashCode()) {
|
||||
false
|
||||
} else {
|
||||
this.name == other.name
|
||||
}
|
||||
this.registries = null
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return name
|
||||
}
|
||||
|
||||
val hasOffhand = versionId >= V_15W31A
|
||||
val flattened: Boolean = versionId >= ProtocolDefinition.FLATTING_VERSION_ID
|
||||
val hasOffhand: Boolean = versionId >= V_15W31A
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ enum class VersionTypes {
|
||||
private val SNAPSHOT_DETECT_REGEX = "(\\d{2}w\\d{2})[a-f]|(1.\\d{1,2}(.\\d+)?-?(rc|pre)\\d*)".toRegex()
|
||||
|
||||
@Deprecated(message = "Should be saved in the versions.json")
|
||||
operator fun get(version: Version): VersionTypes {
|
||||
operator fun get(version: de.bixilon.minosoft.data.registries.versions.Version): VersionTypes {
|
||||
if (SNAPSHOT_DETECT_REGEX.matches(version.name)) {
|
||||
return SNAPSHOT
|
||||
}
|
||||
|
@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.registries.versions;
|
||||
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import de.bixilon.minosoft.data.registries.registries.Registries;
|
||||
import de.bixilon.minosoft.protocol.protocol.PacketTypes;
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolStates;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Deprecated
|
||||
public class Versions {
|
||||
public static final Version AUTOMATIC_VERSION = new Version("Automatic", -1, -1, new HashMap<>(), new HashMap<>());
|
||||
public static final HashBiMap<Integer, @NonNull Version> VERSION_ID_MAP = HashBiMap.create(500);
|
||||
private static final HashBiMap<Integer, @NonNull Version> VERSION_PROTOCOL_ID_MAP = HashBiMap.create(500);
|
||||
private static final HashBiMap<String, @NonNull Version> VERSION_NAME_MAP = HashBiMap.create(500);
|
||||
public static Registries PRE_FLATTENING_MAPPING;
|
||||
public static Version PRE_FLATTENING_VERSION;
|
||||
|
||||
public static Version getVersionById(int versionId) {
|
||||
return VERSION_ID_MAP.get(versionId);
|
||||
}
|
||||
|
||||
public static Version getVersionByProtocolId(int protocolId) {
|
||||
return VERSION_PROTOCOL_ID_MAP.get(protocolId);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Version getVersionByName(@Nullable final String name) {
|
||||
if ("automatic".equals(name)) {
|
||||
return AUTOMATIC_VERSION;
|
||||
}
|
||||
return VERSION_NAME_MAP.get(name);
|
||||
}
|
||||
|
||||
public static void loadAvailableVersions(JsonObject json) {
|
||||
for (String versionId : json.keySet()) {
|
||||
loadVersion(json, versionId);
|
||||
}
|
||||
}
|
||||
|
||||
private static Version loadVersion(JsonObject json, String versionIdString) {
|
||||
JsonObject versionJson = json.getAsJsonObject(versionIdString);
|
||||
String versionName = versionJson.get("name").getAsString();
|
||||
int versionId = Integer.parseInt(versionIdString);
|
||||
if (VERSION_ID_MAP.containsKey(versionId)) {
|
||||
// already loaded, skip
|
||||
return VERSION_ID_MAP.get(versionId);
|
||||
}
|
||||
|
||||
Map<ProtocolStates, HashBiMap<PacketTypes.C2S, Integer>> c2sMapping;
|
||||
Map<ProtocolStates, HashBiMap<PacketTypes.S2C, Integer>> s2cMapping;
|
||||
if (versionJson.get("mapping").isJsonPrimitive()) {
|
||||
// inherits or copies mapping from an other version
|
||||
Version parent = VERSION_ID_MAP.get(versionJson.get("mapping").getAsInt());
|
||||
if (parent == null) {
|
||||
parent = loadVersion(json, versionJson.get("mapping").getAsString());
|
||||
}
|
||||
c2sMapping = parent.getC2SPacketMapping();
|
||||
s2cMapping = parent.getS2CPacketMapping();
|
||||
} else {
|
||||
JsonObject mappingJson = versionJson.getAsJsonObject("mapping");
|
||||
c2sMapping = new HashMap<>();
|
||||
|
||||
for (JsonElement packetElement : mappingJson.getAsJsonArray("c2s")) {
|
||||
PacketTypes.C2S packet = PacketTypes.C2S.valueOf(packetElement.getAsString());
|
||||
if (!c2sMapping.containsKey(packet.getState())) {
|
||||
c2sMapping.put(packet.getState(), HashBiMap.create(30));
|
||||
}
|
||||
c2sMapping.get(packet.getState()).put(packet, c2sMapping.get(packet.getState()).size());
|
||||
}
|
||||
s2cMapping = new HashMap<>();
|
||||
for (JsonElement packetElement : mappingJson.getAsJsonArray("s2c")) {
|
||||
PacketTypes.S2C packet = PacketTypes.S2C.valueOf(packetElement.getAsString());
|
||||
if (!s2cMapping.containsKey(packet.getState())) {
|
||||
s2cMapping.put(packet.getState(), HashBiMap.create(100));
|
||||
}
|
||||
s2cMapping.get(packet.getState()).put(packet, s2cMapping.get(packet.getState()).size());
|
||||
}
|
||||
}
|
||||
int protocolId = versionId;
|
||||
if (versionJson.has("protocol_id")) {
|
||||
protocolId = versionJson.get("protocol_id").getAsInt();
|
||||
}
|
||||
Version version = new Version(versionName, versionId, protocolId, c2sMapping, s2cMapping);
|
||||
VERSION_ID_MAP.put(version.getVersionId(), version);
|
||||
VERSION_PROTOCOL_ID_MAP.put(version.getProtocolId(), version);
|
||||
VERSION_NAME_MAP.put(version.getName(), version);
|
||||
if (version.getVersionId() == ProtocolDefinition.PRE_FLATTENING_VERSION_ID) {
|
||||
PRE_FLATTENING_VERSION = version;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package de.bixilon.minosoft.data.registries.versions
|
||||
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.assets.util.FileUtil.readJson
|
||||
import de.bixilon.minosoft.protocol.protocol.PacketTypes
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolStates
|
||||
import de.bixilon.minosoft.util.KUtil.toInt
|
||||
import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||
|
||||
object Versions : Iterable<Version> {
|
||||
private val VERSIONS_INDEX = "minosoft:mapping/versions.json".toResourceLocation()
|
||||
val AUTOMATIC = Version("Automatic", -1, -1, mapOf(), mapOf())
|
||||
private val VERSIONS_BY_NAME: MutableMap<String, Version> = mutableMapOf()
|
||||
private val VERSIONS_BY_ID: MutableMap<Int, Version> = mutableMapOf()
|
||||
private val VERSIONS_BY_PROTOCOL: MutableMap<Int, Version> = mutableMapOf()
|
||||
|
||||
private fun addVersion(version: Version) {
|
||||
VERSIONS_BY_NAME.put(version.name, version)?.let { throw IllegalStateException("Duplicated version name: ${version.name}") }
|
||||
VERSIONS_BY_ID.put(version.versionId, version)?.let { throw IllegalStateException("Duplicated version id: ${version.name}") }
|
||||
VERSIONS_BY_PROTOCOL.put(version.protocolId, version)?.let { throw IllegalStateException("Duplicated protocol id: ${version.name}") }
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun load() {
|
||||
val index: Map<String, Map<String, Any>> = Minosoft.MINOSOFT_ASSETS_MANAGER[VERSIONS_INDEX].readJson()
|
||||
|
||||
fun loadVersion(versionId: Int, data: Map<String, Any> = index[versionId.toString()]!!): Version {
|
||||
VERSIONS_BY_ID[versionId]?.let { return it }
|
||||
|
||||
|
||||
val s2cPackets: Map<ProtocolStates, Array<PacketTypes.S2C>>
|
||||
val c2sPackets: Map<ProtocolStates, Array<PacketTypes.C2S>>
|
||||
|
||||
when (val mapping = data["mapping"]) {
|
||||
is Int -> {
|
||||
val mappingVersion = loadVersion(mapping)
|
||||
s2cPackets = mappingVersion.s2cPackets
|
||||
c2sPackets = mappingVersion.c2sPackets
|
||||
}
|
||||
is Map<*, *> -> {
|
||||
mapping["s2c"].unsafeCast<List<String>>().let {
|
||||
val map: MutableMap<ProtocolStates, MutableList<PacketTypes.S2C>> = mutableMapOf()
|
||||
for (packetName in it) {
|
||||
val packetType = PacketTypes.S2C[packetName]
|
||||
map.getOrPut(packetType.state) { mutableListOf() } += packetType
|
||||
}
|
||||
val mapOut: MutableMap<ProtocolStates, Array<PacketTypes.S2C>> = mutableMapOf()
|
||||
for ((state, types) in map) {
|
||||
mapOut[state] = types.toTypedArray()
|
||||
}
|
||||
s2cPackets = mapOut.toMap()
|
||||
}
|
||||
|
||||
mapping["c2s"].unsafeCast<List<String>>().let {
|
||||
val map: MutableMap<ProtocolStates, MutableList<PacketTypes.C2S>> = mutableMapOf()
|
||||
for (packetName in it) {
|
||||
val packetType = PacketTypes.C2S[packetName]
|
||||
map.getOrPut(packetType.state) { mutableListOf() } += packetType
|
||||
}
|
||||
val mapOut: MutableMap<ProtocolStates, Array<PacketTypes.C2S>> = mutableMapOf()
|
||||
for ((state, types) in map) {
|
||||
mapOut[state] = types.toTypedArray()
|
||||
}
|
||||
c2sPackets = mapOut.toMap()
|
||||
}
|
||||
|
||||
}
|
||||
else -> TODO("Can not create version mapping $mapping")
|
||||
}
|
||||
|
||||
|
||||
val version = Version(
|
||||
name = data["name"].toString(),
|
||||
versionId = versionId,
|
||||
protocolId = data["protocol_id"]?.toInt() ?: versionId,
|
||||
s2cPackets = s2cPackets,
|
||||
c2sPackets = c2sPackets,
|
||||
)
|
||||
addVersion(version)
|
||||
return version
|
||||
}
|
||||
|
||||
for ((versionId, data) in index) {
|
||||
loadVersion(versionId.toInt(), data)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(name: String?): Version? {
|
||||
return VERSIONS_BY_NAME[name]
|
||||
}
|
||||
|
||||
fun getById(versionId: Int): Version? {
|
||||
return VERSIONS_BY_ID[versionId]
|
||||
}
|
||||
|
||||
fun getByProtocol(protocolId: Int): Version? {
|
||||
return VERSIONS_BY_PROTOCOL[protocolId]
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<Version> {
|
||||
return VERSIONS_BY_NAME.values.iterator()
|
||||
}
|
||||
}
|
@ -129,7 +129,7 @@ class ErosCrashReport : JavaFXWindowController() {
|
||||
}
|
||||
})
|
||||
tryCatch(executor = {
|
||||
for (connection in PlayConnection.ACTIVE_CONENCTIONS.toSynchronizedSet()) {
|
||||
for (connection in PlayConnection.ACTIVE_CONNECTIONS.toSynchronizedSet()) {
|
||||
connection.disconnect()
|
||||
}
|
||||
})
|
||||
|
@ -75,7 +75,7 @@ class ServerModifyDialog(
|
||||
private fun refreshVersions() {
|
||||
val selected = forcedVersionFX.selectionModel.selectedItem
|
||||
forcedVersionFX.items.clear()
|
||||
for (version in Versions.VERSION_ID_MAP.values) {
|
||||
for (version in Versions) {
|
||||
if (version.type == VersionTypes.RELEASE && !showReleasesFX.isSelected) {
|
||||
continue
|
||||
}
|
||||
@ -85,14 +85,14 @@ class ServerModifyDialog(
|
||||
forcedVersionFX.items += version
|
||||
}
|
||||
|
||||
forcedVersionFX.items += Versions.AUTOMATIC_VERSION
|
||||
forcedVersionFX.items += Versions.AUTOMATIC
|
||||
|
||||
forcedVersionFX.items.sortByDescending { it.sortingId }
|
||||
|
||||
if (forcedVersionFX.items.contains(selected)) {
|
||||
forcedVersionFX.selectionModel.select(selected)
|
||||
} else {
|
||||
forcedVersionFX.selectionModel.select(Versions.AUTOMATIC_VERSION)
|
||||
forcedVersionFX.selectionModel.select(Versions.AUTOMATIC)
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ class ServerModifyDialog(
|
||||
super.updateItem(version, empty)
|
||||
version ?: return
|
||||
|
||||
text = if (version == Versions.AUTOMATIC_VERSION) {
|
||||
text = if (version == Versions.AUTOMATIC) {
|
||||
Minosoft.LANGUAGE_MANAGER.translate(VERSION_AUTOMATIC).message
|
||||
} else {
|
||||
"${version.name} (${version.type.name.lowercase()})"
|
||||
@ -146,12 +146,12 @@ class ServerModifyDialog(
|
||||
refreshVersions()
|
||||
|
||||
if (server == null) {
|
||||
forcedVersionFX.selectionModel.select(Versions.AUTOMATIC_VERSION)
|
||||
forcedVersionFX.selectionModel.select(Versions.AUTOMATIC)
|
||||
// add
|
||||
descriptionFX.text = ADD_DESCRIPTION
|
||||
modifyServerButtonFX.ctext = ADD_UPDATE_BUTTON
|
||||
} else {
|
||||
forcedVersionFX.selectionModel.select(server.forcedVersion ?: Versions.AUTOMATIC_VERSION)
|
||||
forcedVersionFX.selectionModel.select(server.forcedVersion ?: Versions.AUTOMATIC)
|
||||
descriptionFX.text = EDIT_DESCRIPTION
|
||||
modifyServerButtonFX.ctext = EDIT_UPDATE_BUTTON
|
||||
|
||||
@ -173,7 +173,7 @@ class ServerModifyDialog(
|
||||
if (modifyServerButtonFX.isDisable) {
|
||||
return
|
||||
}
|
||||
val forcedVersion = (forcedVersionFX.selectionModel.selectedItem == Versions.AUTOMATIC_VERSION).decide(null) { forcedVersionFX.selectionModel.selectedItem }
|
||||
val forcedVersion = (forcedVersionFX.selectionModel.selectedItem == Versions.AUTOMATIC).decide(null) { forcedVersionFX.selectionModel.selectedItem }
|
||||
DefaultThreadPool += { onUpdate(serverNameFX.text.isBlank().decide({ serverAddressFX.text.toString() }, { serverNameFX.text.trim() }), serverAddressFX.text, forcedVersion, profiles) }
|
||||
stage.close()
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ class WorldRenderer(
|
||||
|
||||
override fun init() {
|
||||
val asset = AssetsVersionProperties[connection.version]!!
|
||||
val zip = FileUtil.readFile(FileAssetsUtil.getPath(asset.clientJarHash)).readArchive()
|
||||
val zip = FileUtil.readFile(FileAssetsUtil.getPath(asset.jarAssetsHash)).readArchive()
|
||||
val modelLoader = ModelLoader(zip, renderWindow)
|
||||
modelLoader.load()
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.connection.play
|
||||
|
||||
import de.bixilon.minosoft.Minosoft
|
||||
import de.bixilon.minosoft.assets.multi.PriorityAssetsManager
|
||||
import de.bixilon.minosoft.assets.AssetsLoader
|
||||
import de.bixilon.minosoft.assets.AssetsManager
|
||||
import de.bixilon.minosoft.config.profile.ConnectionProfiles
|
||||
import de.bixilon.minosoft.data.ChatTextPositions
|
||||
import de.bixilon.minosoft.data.accounts.Account
|
||||
@ -24,7 +24,6 @@ import de.bixilon.minosoft.data.language.LanguageManager
|
||||
import de.bixilon.minosoft.data.physics.CollisionDetector
|
||||
import de.bixilon.minosoft.data.player.LocalPlayerEntity
|
||||
import de.bixilon.minosoft.data.player.tab.TabList
|
||||
import de.bixilon.minosoft.data.registries.RegistriesLoadingException
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||
import de.bixilon.minosoft.data.registries.ResourceLocationAble
|
||||
import de.bixilon.minosoft.data.registries.recipes.Recipes
|
||||
@ -83,7 +82,7 @@ class PlayConnection(
|
||||
@Deprecated(message = "PacketSender is deprecated")
|
||||
val sender = PacketSender(this)
|
||||
val serverInfo = ServerInfo()
|
||||
lateinit var assetsManager: PriorityAssetsManager
|
||||
lateinit var assetsManager: AssetsManager
|
||||
private set
|
||||
val tags: MutableMap<ResourceLocation, Map<ResourceLocation, Tag<Any>>> = synchronizedMapOf()
|
||||
lateinit var language: LanguageManager
|
||||
@ -129,7 +128,7 @@ class PlayConnection(
|
||||
when (value) {
|
||||
ProtocolStates.HANDSHAKING -> {
|
||||
state = PlayConnectionStates.HANDSHAKING
|
||||
ACTIVE_CONENCTIONS += this
|
||||
ACTIVE_CONNECTIONS += this
|
||||
for ((validators, invokers) in GlobalEventMaster.specificEventInvokers) {
|
||||
var valid = false
|
||||
for (serverAddress in validators) {
|
||||
@ -206,7 +205,7 @@ class PlayConnection(
|
||||
TimeWorker.removeTask(randomTickTask)
|
||||
}
|
||||
state = PlayConnectionStates.DISCONNECTED
|
||||
ACTIVE_CONENCTIONS -= this
|
||||
ACTIVE_CONNECTIONS -= this
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
@ -218,16 +217,20 @@ class PlayConnection(
|
||||
try {
|
||||
state = PlayConnectionStates.LOADING
|
||||
fireEvent(RegistriesLoadEvent(this, registries, RegistriesLoadEvent.States.PRE))
|
||||
version.load(latch) // ToDo: show gui loader
|
||||
assetsManager = PriorityAssetsManager(Minosoft.MINOSOFT_ASSETS_MANAGER)
|
||||
language = LanguageManager.load(profiles.connection.language ?: profiles.eros.general.language, version)
|
||||
version.load(profiles.resources)
|
||||
registries.parentRegistries = version.registries
|
||||
|
||||
assetsManager = AssetsLoader.create(profiles.resources, version)
|
||||
Log.log(LogMessageType.ASSETS, LogLevels.INFO) { "Downloading and verifying assets. This might take a while..." }
|
||||
assetsManager.load(latch)
|
||||
Log.log(LogMessageType.ASSETS, LogLevels.INFO) { "Assets verified!" }
|
||||
|
||||
language = LanguageManager.load(profiles.connection.language ?: profiles.eros.general.language, version, assetsManager)
|
||||
|
||||
fireEvent(RegistriesLoadEvent(this, registries, RegistriesLoadEvent.States.POST))
|
||||
player = LocalPlayerEntity(account, this)
|
||||
|
||||
if (!RunConfiguration.DISABLE_RENDERING) {
|
||||
assetsManager.add(version.jarAssetsManager)
|
||||
assetsManager.add(version.indexAssetsManager)
|
||||
val renderer = Rendering(this)
|
||||
this.rendering = renderer
|
||||
val renderLatch = CountUpAndDownLatch(0, latch)
|
||||
@ -239,26 +242,28 @@ class PlayConnection(
|
||||
state = PlayConnectionStates.ESTABLISHING
|
||||
} catch (exception: Throwable) {
|
||||
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.FATAL) { exception }
|
||||
Log.log(LogMessageType.VERSION_LOADING, level = LogLevels.FATAL) { "Could not load version $version. This version seems to be unsupported" }
|
||||
version.unload()
|
||||
error = RegistriesLoadingException("Registries could not be loaded", exception)
|
||||
if (this::assetsManager.isInitialized) {
|
||||
assetsManager.unload()
|
||||
}
|
||||
error = exception
|
||||
retry = false
|
||||
}
|
||||
latch.dec()
|
||||
}
|
||||
|
||||
|
||||
override fun getPacketId(packetType: PacketTypes.C2S): Int {
|
||||
return version.getPacketId(packetType) ?: Protocol.getPacketId(packetType) ?: error("Can not find packet $packetType for $version")
|
||||
// ToDo: Improve speed
|
||||
return version.c2sPackets[packetType.state]?.indexOf(packetType) ?: Protocol.getPacketId(packetType) ?: error("Can not find packet $packetType for $version")
|
||||
}
|
||||
|
||||
override fun getPacketById(packetId: Int): PacketTypes.S2C {
|
||||
return version.getPacketById(protocolState, packetId) ?: Protocol.getPacketById(protocolState, packetId) ?: let {
|
||||
return version.s2cPackets[protocolState]?.getOrNull(packetId) ?: Protocol.getPacketById(protocolState, packetId) ?: let {
|
||||
// wtf, notchain sends play disconnect packet in login state...
|
||||
if (protocolState != ProtocolStates.LOGIN) {
|
||||
return@let null
|
||||
}
|
||||
val playPacket = version.getPacketById(ProtocolStates.PLAY, packetId)
|
||||
val playPacket = version.s2cPackets[ProtocolStates.PLAY]?.getOrNull(packetId)
|
||||
if (playPacket == PacketTypes.S2C.PLAY_KICK) {
|
||||
return@let playPacket
|
||||
}
|
||||
@ -301,6 +306,6 @@ class PlayConnection(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ACTIVE_CONENCTIONS: MutableSet<PlayConnection> = synchronizedSetOf()
|
||||
val ACTIVE_CONNECTIONS: MutableSet<PlayConnection> = synchronizedSetOf()
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ class ClientSettingsManager(
|
||||
return
|
||||
}
|
||||
this.language = language
|
||||
connection.language = LanguageManager.load(language, connection.version)
|
||||
connection.language = LanguageManager.load(language, connection.version, connection.assetsManager)
|
||||
sendClientSettings()
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ class StatusConnection(
|
||||
when (value) {
|
||||
ProtocolStates.HANDSHAKING -> {
|
||||
state = StatusConnectionStates.HANDSHAKING
|
||||
network.sendPacket(HandshakeC2SP(realAddress!!, ProtocolStates.STATUS, Versions.AUTOMATIC_VERSION.protocolId))
|
||||
network.sendPacket(HandshakeC2SP(realAddress!!, ProtocolStates.STATUS, Versions.AUTOMATIC.protocolId))
|
||||
protocolState = ProtocolStates.STATUS
|
||||
}
|
||||
ProtocolStates.STATUS -> {
|
||||
|
@ -24,14 +24,14 @@ import de.bixilon.minosoft.util.logging.LogLevels
|
||||
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||
|
||||
class ClientSettingsC2SP(
|
||||
val locale: String = "en_US",
|
||||
var chatColors: Boolean = true,
|
||||
val viewDistance: Int = 10,
|
||||
val chatMode: ChatModes = ChatModes.EVERYTHING,
|
||||
val skinParts: Array<SkinParts> = SkinParts.VALUES,
|
||||
val mainArm: Arms = Arms.RIGHT,
|
||||
val disableTextFiltering: Boolean = true,
|
||||
val allowListing: Boolean = true,
|
||||
val locale: String,
|
||||
var chatColors: Boolean,
|
||||
val viewDistance: Int,
|
||||
val chatMode: ChatModes,
|
||||
val skinParts: Array<SkinParts>,
|
||||
val mainArm: Arms,
|
||||
val disableTextFiltering: Boolean,
|
||||
val allowListing: Boolean,
|
||||
) : PlayC2SPacket {
|
||||
|
||||
override fun write(buffer: PlayOutByteBuffer) {
|
||||
|
@ -31,7 +31,7 @@ class ServerStatusResponseS2CP(buffer: InByteBuffer) : StatusS2CPacket() {
|
||||
|
||||
override fun handle(connection: StatusConnection) {
|
||||
connection.lastServerStatus = status
|
||||
val version: Version? = Versions.getVersionByProtocolId(status.protocolId ?: -1)
|
||||
val version: Version? = Versions.getByProtocol(status.protocolId ?: -1)
|
||||
if (version == null) {
|
||||
Log.log(LogMessageType.NETWORK_STATUS, LogLevels.WARN) { "Server is running on unknown version (protocolId=${status.protocolId})" }
|
||||
} else {
|
||||
|
@ -49,6 +49,8 @@ import de.bixilon.minosoft.protocol.packets.s2c.play.scoreboard.teams.TeamsS2CF
|
||||
import de.bixilon.minosoft.protocol.packets.s2c.play.title.*
|
||||
import de.bixilon.minosoft.protocol.packets.s2c.status.ServerStatusResponseS2CP
|
||||
import de.bixilon.minosoft.protocol.packets.s2c.status.StatusPongS2CP
|
||||
import de.bixilon.minosoft.util.KUtil
|
||||
import de.bixilon.minosoft.util.enum.ValuesEnum
|
||||
|
||||
class PacketTypes {
|
||||
|
||||
@ -115,8 +117,10 @@ class PacketTypes {
|
||||
|
||||
val state: ProtocolStates = ProtocolStates.valueOf(name.split("_".toRegex()).toTypedArray()[0])
|
||||
|
||||
companion object {
|
||||
companion object : ValuesEnum<C2S> {
|
||||
private val MAPPING: Map<Class<out C2SPacket>, C2S>
|
||||
override val VALUES: Array<C2S> = values()
|
||||
override val NAME_MAP: Map<String, C2S> = KUtil.getEnumValues(VALUES)
|
||||
|
||||
init {
|
||||
val mapping: MutableMap<Class<out C2SPacket>, C2S> = mutableMapOf()
|
||||
@ -288,5 +292,11 @@ class PacketTypes {
|
||||
|
||||
|
||||
val state: ProtocolStates = ProtocolStates.valueOf(name.split("_".toRegex()).toTypedArray()[0])
|
||||
|
||||
|
||||
companion object : ValuesEnum<S2C> {
|
||||
override val VALUES: Array<S2C> = values()
|
||||
override val NAME_MAP: Map<String, S2C> = KUtil.getEnumValues(VALUES)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ class PlayInByteBuffer : InByteBuffer {
|
||||
}
|
||||
val count = readUnsignedByte()
|
||||
var metaData = 0
|
||||
if (connection.version.isFlattened()) {
|
||||
if (!connection.version.flattened) {
|
||||
metaData = readUnsignedShort()
|
||||
}
|
||||
val nbt = readNBTTag(versionId < V_14W28B)?.compoundCast()
|
||||
|
@ -40,11 +40,11 @@ object AutoConnect {
|
||||
// ToDo: Show those connections in eros
|
||||
val split = connectString.split(',')
|
||||
val address = split[0]
|
||||
val version = Versions.getVersionByName(split.getOrNull(1) ?: "automatic") ?: throw IllegalArgumentException("Auto connect: Version not found!")
|
||||
val version = Versions[split.getOrNull(1) ?: "automatic"] ?: throw IllegalArgumentException("Auto connect: Version not found!")
|
||||
val accountProfile = AccountProfileManager.selected
|
||||
val account = accountProfile.entries[split.getOrNull(2)] ?: accountProfile.selected ?: throw RuntimeException("Auto connect: Account not found! Have you started normal before or added an account?")
|
||||
|
||||
if (version == Versions.AUTOMATIC_VERSION) {
|
||||
if (version == Versions.AUTOMATIC) {
|
||||
Log.log(LogMessageType.AUTO_CONNECT, LogLevels.INFO) { "Pinging server to get version..." }
|
||||
val ping = StatusConnection(address)
|
||||
ping.ping()
|
||||
|
@ -53,7 +53,7 @@ object KUtil {
|
||||
val ret: MutableMap<String, T> = mutableMapOf()
|
||||
|
||||
for (value in values) {
|
||||
ret[value.name.lowercase(Locale.getDefault())] = value
|
||||
ret[value.name.lowercase()] = value
|
||||
|
||||
if (value is AliasableEnum) {
|
||||
for (name in value.names) {
|
||||
|
@ -30,7 +30,7 @@ object ShutdownManager {
|
||||
|
||||
fun shutdown(message: String? = null, reason: ShutdownReasons = ShutdownReasons.UNKNOWN) {
|
||||
Log.log(LogMessageType.GENERAL, LogLevels.INFO) { "Shutting down..." }
|
||||
for (connection in PlayConnection.ACTIVE_CONENCTIONS.toSynchronizedSet()) {
|
||||
for (connection in PlayConnection.ACTIVE_CONNECTIONS.toSynchronizedSet()) {
|
||||
connection.disconnect()
|
||||
}
|
||||
FileWatcherService.stop()
|
||||
|
@ -36,7 +36,6 @@ import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.*;
|
||||
|
||||
@ -46,7 +45,7 @@ public final class Util {
|
||||
public static final char[] RANDOM_STRING_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
|
||||
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
public static final Gson GSON = new Gson();
|
||||
private static final Random THREAD_LOCAL_RANDOM = ThreadLocalRandom.current();
|
||||
private static final Random RANDOM = new Random();
|
||||
private static final Field JSON_READER_POS_FIELD;
|
||||
private static final Field JSON_READER_LINE_START_FIELD;
|
||||
|
||||
@ -251,11 +250,11 @@ public final class Util {
|
||||
}
|
||||
|
||||
public static char getRandomChar(char[] chars) {
|
||||
return chars[(THREAD_LOCAL_RANDOM.nextInt(chars.length))];
|
||||
return chars[(RANDOM.nextInt(chars.length))];
|
||||
}
|
||||
|
||||
public static char getRandomChar() {
|
||||
return (char) THREAD_LOCAL_RANDOM.nextInt();
|
||||
return (char) RANDOM.nextInt();
|
||||
}
|
||||
|
||||
public static String getStringBetween(String search, String first, String second) {
|
||||
|
@ -22,7 +22,7 @@ interface ValuesEnum<T : Enum<*>> {
|
||||
}
|
||||
|
||||
operator fun get(name: String): T {
|
||||
return NAME_MAP[name] ?: throw IllegalArgumentException("Can not find enum value: $name")
|
||||
return NAME_MAP[name.lowercase()] ?: throw IllegalArgumentException("Can not find enum value: $name")
|
||||
}
|
||||
|
||||
fun next(current: T): T {
|
||||
|
Loading…
x
Reference in New Issue
Block a user