package ru.dbotthepony.kstarbound import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonParser import ru.dbotthepony.kstarbound.api.IVFS import ru.dbotthepony.kstarbound.api.PhysicalFS import ru.dbotthepony.kstarbound.defs.TileDefinition import ru.dbotthepony.kstarbound.defs.TileDefinitionBuilder import ru.dbotthepony.kstarbound.io.StarboundPak import ru.dbotthepony.kstarbound.world.World import java.io.* import java.nio.ByteBuffer import java.util.* import kotlin.collections.ArrayList import kotlin.collections.HashMap const val METRES_IN_STARBOUND_UNIT = 0.25 const val METRES_IN_STARBOUND_UNITf = 0.25f const val PIXELS_IN_STARBOUND_UNIT = 8.0 const val PIXELS_IN_STARBOUND_UNITf = 8.0f class TileDefLoadingException(message: String, cause: Throwable? = null) : IllegalStateException(message, cause) object Starbound : IVFS { private val tiles = HashMap() val tilesAccess = object : Map by tiles {} var initializing = false private set var initialized = false private set var terminateLoading = false private val archivePaths = ArrayList() private val fileSystems = ArrayList() fun addFilePath(path: File) { fileSystems.add(PhysicalFS(path)) } /** * Добавляет уже прочитанный pak */ fun addPak(pak: StarboundPak) { fileSystems.add(pak) } /** * Добавляет pak к чтению при initializeGame */ fun addPakPath(pak: File) { archivePaths.add(pak) } fun loadJson(path: String): JsonElement { return JsonParser.parseReader(getReader(path)) } fun getTileDefinition(name: String) = tiles[name] private val initCallbacks = ArrayList<() -> Unit>() fun initializeGame(callback: (finished: Boolean, replaceStatus: Boolean, status: String) -> Unit) { if (initializing) { throw IllegalStateException("Already initializing!") } if (initialized) { throw IllegalStateException("Already initialized!") } initializing = true Thread({ val time = System.currentTimeMillis() if (archivePaths.isNotEmpty()) { callback(false, false, "Reading pak archives...") for (path in archivePaths) { callback(false, false, "Reading ${path.name}...") addPak(StarboundPak(path) { _, status -> callback(false, true, "${path.name}: $status") }) } } callback(false, false, "Loading materials...") loadTileMaterials { if (terminateLoading) { throw InterruptedException("Game is terminating") } callback(false, true, it) } callback(false, true, "Loaded materials") initializing = false initialized = true callback(true, false, "Finished loading in ${System.currentTimeMillis() - time}ms") }, "Asset Loader").start() } override fun pathExists(path: String): Boolean { for (fs in fileSystems) { if (fs.pathExists(path)) { return true } } return false } override fun readOrNull(path: String): ByteBuffer? { for (fs in fileSystems) { if (fs.pathExists(path)) { return fs.read(path) } } return null } override fun listFiles(path: String): List { val listing = mutableListOf() for (fs in fileSystems) { listing.addAll(fs.listFiles(path)) } return listing } fun onInitialize(callback: () -> Unit) { if (initialized) { callback() } else { initCallbacks.add(callback) } } fun pollCallbacks() { if (initialized && initCallbacks.isNotEmpty()) { for (callback in initCallbacks) { callback() } initCallbacks.clear() } } private fun loadTileMaterials(callback: (String) -> Unit) { for (fs in fileSystems) { for (listedFile in fs.listFiles("tiles/materials")) { if (listedFile.endsWith(".material")) { try { callback("Loading $listedFile") val tileDef = TileDefinitionBuilder.fromJson(JsonParser.parseReader(getReader(listedFile)) as JsonObject).build("/tiles/materials") check(tiles[tileDef.materialName] == null) { "Already has material with ID ${tileDef.materialName} loaded!" } tiles[tileDef.materialName] = tileDef } catch (err: Throwable) { throw TileDefLoadingException("Loading tile file $listedFile", err) } } } } } }