More stuff
Scrolling callbacks Improved btree reader noclip controls
This commit is contained in:
parent
dcc06319c6
commit
51a43d70be
@ -40,6 +40,7 @@ fun main() {
|
||||
}
|
||||
|
||||
val db = BTreeDB(File("F:\\SteamLibrary\\steamapps\\common\\Starbound - Unstable\\storage\\universe\\389760395_938904237_-238610574_5.world"))
|
||||
//val db = BTreeDB(File("world.world"))
|
||||
|
||||
/*if (true) {
|
||||
val a = System.currentTimeMillis()
|
||||
@ -89,6 +90,7 @@ fun main() {
|
||||
|
||||
//Starbound.addFilePath(File("./unpacked_assets/"))
|
||||
Starbound.addPakPath(File("J:\\Steam\\steamapps\\common\\Starbound\\assets\\packed.pak"))
|
||||
//Starbound.addPakPath(File("packed.pak"))
|
||||
|
||||
Starbound.initializeGame { finished, replaceStatus, status ->
|
||||
client.putDebugLog(status, replaceStatus)
|
||||
@ -163,14 +165,19 @@ fun main() {
|
||||
}
|
||||
|
||||
println("$find $set $parse")
|
||||
|
||||
//client.world!!.parallax = Starbound.parallaxAccess["garden"]
|
||||
}
|
||||
|
||||
//ent.position += Vector2d(y = 14.0, x = -10.0)
|
||||
ent.position = Vector2d(128.0 + 16.0, 672.0 + 48.0)
|
||||
ent.position = Vector2d(600.0 + 16.0, 721.0 + 48.0)
|
||||
client.camera.pos.x = 616f
|
||||
client.camera.pos.y = 721f
|
||||
|
||||
client.onDrawGUI {
|
||||
client.gl.font.render("${ent.position}", y = 100f, scale = 0.25f)
|
||||
client.gl.font.render("${ent.movement.velocity}", y = 120f, scale = 0.25f)
|
||||
client.gl.font.render("${client.camera.pos}", y = 140f, scale = 0.25f)
|
||||
}
|
||||
|
||||
client.onPreDrawWorld {
|
||||
@ -178,8 +185,6 @@ fun main() {
|
||||
//client.camera.pos.y = ent.pos.y.toFloat()
|
||||
}
|
||||
|
||||
client.camera.pos.y = 10f
|
||||
|
||||
client.gl.box2dRenderer.drawShapes = false
|
||||
client.gl.box2dRenderer.drawPairs = false
|
||||
client.gl.box2dRenderer.drawAABB = false
|
||||
@ -187,19 +192,33 @@ fun main() {
|
||||
|
||||
ent.spawn()
|
||||
|
||||
client.input.addScrollCallback { _, x, y ->
|
||||
if (y > 0.0) {
|
||||
client.settings.scale *= y.toFloat() * 2f
|
||||
} else if (y < 0.0) {
|
||||
client.settings.scale /= -y.toFloat() * 2f
|
||||
}
|
||||
}
|
||||
|
||||
while (client.renderFrame()) {
|
||||
Starbound.pollCallbacks()
|
||||
|
||||
//ent.think(client.frameRenderTime)
|
||||
client.camera.pos.x = ent.position.x.toFloat()
|
||||
client.camera.pos.y = ent.position.y.toFloat()
|
||||
//client.camera.pos.x = ent.position.x.toFloat()
|
||||
//client.camera.pos.y = ent.position.y.toFloat()
|
||||
|
||||
client.camera.pos.x += if (client.input.KEY_LEFT_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||
client.camera.pos.x += if (client.input.KEY_RIGHT_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||
|
||||
client.camera.pos.y += if (client.input.KEY_UP_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||
client.camera.pos.y += if (client.input.KEY_DOWN_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.scale else 0f
|
||||
|
||||
//println(client.camera.velocity.toDoubleVector() * client.frameRenderTime * 0.1)
|
||||
|
||||
//if (ent.onGround)
|
||||
//ent.velocity += client.camera.velocity.toDoubleVector() * client.frameRenderTime * 0.1
|
||||
|
||||
if (client.input.KEY_LEFT_DOWN) {
|
||||
/*if (client.input.KEY_LEFT_DOWN) {
|
||||
ent.movement.moveDirection = Move.MOVE_LEFT
|
||||
} else if (client.input.KEY_RIGHT_DOWN) {
|
||||
ent.movement.moveDirection = Move.MOVE_RIGHT
|
||||
@ -211,13 +230,13 @@ fun main() {
|
||||
ent.movement.requestJump()
|
||||
} else if (client.input.KEY_SPACE_RELEASED) {
|
||||
ent.movement.recallJump()
|
||||
}
|
||||
}*/
|
||||
|
||||
if (client.input.KEY_ESCAPE_PRESSED) {
|
||||
glfwSetWindowShouldClose(client.window, true)
|
||||
}
|
||||
|
||||
ent.wantsToDuck = client.input.KEY_DOWN_DOWN
|
||||
//ent.wantsToDuck = client.input.KEY_DOWN_DOWN
|
||||
|
||||
//if (chunkA != null && glfwGetTime() < 10.0) {
|
||||
// val tile = Starbound.getTileDefinition("alienrock")
|
||||
|
@ -52,7 +52,7 @@ class ClientWorld(val client: StarboundClient, seed: Long = 0L) : World<ClientWo
|
||||
|
||||
for (layer in parallax.layers) {
|
||||
client.gl.matrixStack.push()
|
||||
client.gl.matrixStack.translateWithMultiplication(x = layer.offset.x.toFloat() / PIXELS_IN_STARBOUND_UNITf / 16f, y = layer.offset.y.toFloat() / PIXELS_IN_STARBOUND_UNITf / 16f)
|
||||
client.gl.matrixStack.translateWithMultiplication(x = layer.offset.x.toFloat() / PIXELS_IN_STARBOUND_UNITf, y = layer.offset.y.toFloat() / PIXELS_IN_STARBOUND_UNITf)
|
||||
|
||||
client.gl.shaderVertexTexture.transform.set(client.gl.matrixStack.last)
|
||||
|
||||
@ -65,16 +65,16 @@ class ClientWorld(val client: StarboundClient, seed: Long = 0L) : World<ClientWo
|
||||
builder.begin()
|
||||
|
||||
for (xPos in DoubleEdgeProgression()) {
|
||||
var x0 = xPos.toFloat() * texture.width / PIXELS_IN_STARBOUND_UNITf / 16f
|
||||
var x1 = (xPos + 1f) * texture.width / PIXELS_IN_STARBOUND_UNITf / 16f
|
||||
var x0 = xPos.toFloat() * texture.width / PIXELS_IN_STARBOUND_UNITf
|
||||
var x1 = (xPos + 1f) * texture.width / PIXELS_IN_STARBOUND_UNITf
|
||||
|
||||
val diffx = layer.parallax.x * centre.x - centre.x
|
||||
val diffy = (layer.parallax.y * (centre.y + 20.0) - centre.y - 20.0).toFloat() / PIXELS_IN_STARBOUND_UNITf / 16f
|
||||
val diffy = (layer.parallax.y * (centre.y + 20.0) - centre.y - 20.0).toFloat() / PIXELS_IN_STARBOUND_UNITf
|
||||
|
||||
x0 += diffx.toFloat() / PIXELS_IN_STARBOUND_UNITf / 16f
|
||||
x1 += diffx.toFloat() / PIXELS_IN_STARBOUND_UNITf / 16f
|
||||
x0 += diffx.toFloat() / PIXELS_IN_STARBOUND_UNITf
|
||||
x1 += diffx.toFloat() / PIXELS_IN_STARBOUND_UNITf
|
||||
|
||||
builder.quadZ(x0, diffy, x1, diffy + texture.height.toFloat() / PIXELS_IN_STARBOUND_UNITf / 16f, 1f, VertexTransformers.uv(0f, 1f, 1f, 0f))
|
||||
builder.quadZ(x0, diffy, x1, diffy + texture.height.toFloat() / PIXELS_IN_STARBOUND_UNITf, 1f, VertexTransformers.uv(0f, 1f, 1f, 0f))
|
||||
|
||||
/*if (x1 < size.mins.x) {
|
||||
break
|
||||
|
@ -117,7 +117,7 @@ class StarboundClient : AutoCloseable {
|
||||
GLFW.glfwMakeContextCurrent(window)
|
||||
|
||||
// vsync
|
||||
GLFW.glfwSwapInterval(1)
|
||||
GLFW.glfwSwapInterval(0)
|
||||
|
||||
GLFW.glfwShowWindow(window)
|
||||
putDebugLog("Initialized GLFW window")
|
||||
|
@ -12,6 +12,8 @@ private interface HowLongHeldDown {
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>?): Double
|
||||
}
|
||||
|
||||
typealias ScrollCallback = (invalidate: () -> Unit, x: Double, y: Double) -> Unit
|
||||
|
||||
@Suppress("unused")
|
||||
class UserInput : IUserInput {
|
||||
fun keyPressed(code: Int) {
|
||||
@ -129,15 +131,77 @@ class UserInput : IUserInput {
|
||||
mappedKey.updateState(action)
|
||||
}
|
||||
|
||||
private var lastScrollUpdate = 0
|
||||
|
||||
private val scrollCallbacks = ArrayList<ScrollCallback>()
|
||||
|
||||
fun addScrollCallback(callback: ScrollCallback): Boolean {
|
||||
if (!scrollCallbacks.contains(callback)) {
|
||||
scrollCallbacks.add(callback)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private var inScrollCallback = false
|
||||
|
||||
fun removeScrollCallback(callback: ScrollCallback): Boolean {
|
||||
if (inScrollCallback) {
|
||||
throw ConcurrentModificationException("Can't remove scroll callback while iterating them, use invalidate function inside scroll callback itself!")
|
||||
}
|
||||
|
||||
return scrollCallbacks.remove(callback)
|
||||
}
|
||||
|
||||
var lastScrollX: Double = 0.0
|
||||
private set
|
||||
|
||||
var lastScrollY: Double = 0.0
|
||||
private set
|
||||
|
||||
fun callScroll(x: Double, y: Double) {
|
||||
lastScrollX = x
|
||||
lastScrollY = y
|
||||
lastScrollUpdate = frame
|
||||
|
||||
val iterator = scrollCallbacks.iterator()
|
||||
var i = 0
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
i++
|
||||
val ithis = i
|
||||
val value = iterator.next()
|
||||
|
||||
value.invoke({
|
||||
if (i != ithis) {
|
||||
throw IllegalStateException("What the hell did you just do")
|
||||
}
|
||||
|
||||
iterator.remove()
|
||||
}, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
fun installCallback(window: Long) {
|
||||
glfwSetKeyCallback(window) { _, key, scancode, action, mods ->
|
||||
callChange(key, action)
|
||||
}
|
||||
|
||||
glfwSetScrollCallback(window) { _, x, y ->
|
||||
callScroll(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
private var lastTick = 0.0
|
||||
|
||||
var frame = 0
|
||||
private set
|
||||
|
||||
fun think() {
|
||||
val scrollCooldown = lastScrollUpdate != frame
|
||||
frame++
|
||||
|
||||
val thisTime = glfwGetTime()
|
||||
val delta = thisTime - lastTick
|
||||
lastTick = thisTime
|
||||
@ -145,6 +209,11 @@ class UserInput : IUserInput {
|
||||
for (key in userKeys) {
|
||||
key.think(delta, thisTime)
|
||||
}
|
||||
|
||||
if (scrollCooldown) {
|
||||
lastScrollX = 0.0
|
||||
lastScrollY = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
private val keyMap = mapOf(
|
||||
|
@ -1,12 +1,8 @@
|
||||
package ru.dbotthepony.kstarbound.io
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import it.unimi.dsi.fastutil.ints.IntArraySet
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.DataInputStream
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.RandomAccessFile
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
|
||||
private fun readHeader(reader: RandomAccessFile, required: Char) {
|
||||
val read = reader.read()
|
||||
@ -63,7 +59,7 @@ class BTreeDB(val path: File) {
|
||||
readHeader(reader, '5')
|
||||
}
|
||||
|
||||
val blockSize = reader.readInt().toLong()
|
||||
val blockSize = reader.readInt()
|
||||
val dbNameRaw = ByteArray(16).also { reader.read(it) }
|
||||
val indexKeySize = reader.readInt()
|
||||
val useNodeTwo = reader.readBoolean()
|
||||
@ -123,7 +119,7 @@ class BTreeDB(val path: File) {
|
||||
// иначе, ищем следующий блок
|
||||
|
||||
// пропускаем оставшиеся данные, переходим на границу текущего блока-лепестка
|
||||
val delta = (blockSize - 4 - offset).toInt()
|
||||
val delta = (blockSize - 4 - offset)
|
||||
reader.skipBytes(delta)
|
||||
|
||||
// ищем следующий блок с нашими данными
|
||||
@ -217,76 +213,30 @@ class BTreeDB(val path: File) {
|
||||
}
|
||||
|
||||
// мы пришли в лепесток, теперь прямолинейно ищем в linked list
|
||||
var offset = 6
|
||||
val keyCount = reader.readInt()
|
||||
val leafStream = DataInputStream(BufferedInputStream(LeafInputStream(2)))
|
||||
val keyCount = leafStream.readInt()
|
||||
|
||||
for (keyIndex in 0 until keyCount) {
|
||||
// читаем ключ
|
||||
reader.read(keyLoader)
|
||||
offset += indexKeySize
|
||||
leafStream.read(keyLoader)
|
||||
|
||||
// читаем размер данных
|
||||
var (dataLength, readBytes) = reader.readVarIntInfo()
|
||||
offset += readBytes
|
||||
val dataLength = leafStream.readVarInt()
|
||||
|
||||
// это наш блок
|
||||
if (keyLoader.contentEquals(key)) {
|
||||
val binary = ByteArray(dataLength)
|
||||
var binaryOffset = 0
|
||||
|
||||
// читаем данные
|
||||
while (true) {
|
||||
// если конец данных внутри текущего блока, останавливаемся
|
||||
if (offset + dataLength <= blockSize - 4) {
|
||||
reader.readFully(binary, binaryOffset, dataLength)
|
||||
offset += dataLength
|
||||
binaryOffset += dataLength
|
||||
break
|
||||
}
|
||||
|
||||
// иначе, ищем следующий блок
|
||||
|
||||
// пропускаем оставшиеся данные, переходим на границу текущего блока-лепестка
|
||||
val delta = (blockSize - 4 - offset).toInt()
|
||||
reader.readFully(binary, binaryOffset, delta)
|
||||
binaryOffset += delta
|
||||
|
||||
// ищем следующий блок с нашими данными
|
||||
val nextBlockIndex = reader.readInt()
|
||||
seekBlock(nextBlockIndex.toLong())
|
||||
|
||||
// удостоверяемся что мы попали в лепесток
|
||||
check(readBlockType() == TreeBlockType.LEAF) { "Did not hit leaf block" }
|
||||
offset = 2
|
||||
dataLength -= delta
|
||||
if (dataLength == 0) {
|
||||
// нет данных (?)
|
||||
return binary
|
||||
}
|
||||
|
||||
leafStream.readFully(binary)
|
||||
|
||||
return binary
|
||||
} else {
|
||||
// это не наш блок, пропускаем его
|
||||
while (true) {
|
||||
// если конец данных внутри текущего блока, останавливаемся
|
||||
if (offset + dataLength <= blockSize - 4) {
|
||||
reader.skipBytes(dataLength)
|
||||
offset += dataLength
|
||||
break
|
||||
}
|
||||
|
||||
// иначе, ищем следующий блок
|
||||
|
||||
// пропускаем оставшиеся данные, переходим на границу текущего блока-лепестка
|
||||
val delta = (blockSize - 4 - offset).toInt()
|
||||
reader.skipBytes(delta)
|
||||
|
||||
// ищем следующий блок с нашими данными
|
||||
val nextBlockIndex = reader.readInt()
|
||||
seekBlock(nextBlockIndex.toLong())
|
||||
|
||||
// удостоверяемся что мы попали в лепесток
|
||||
check(readBlockType() == TreeBlockType.LEAF) { "Did not hit leaf block" }
|
||||
offset = 2
|
||||
dataLength -= delta
|
||||
}
|
||||
leafStream.skipBytes(dataLength)
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,6 +245,70 @@ class BTreeDB(val path: File) {
|
||||
|
||||
fun seekBlock(id: Long) {
|
||||
require(id >= 0) { "Negative id $id" }
|
||||
require(id * blockSize + blocksOffsetStart < reader.length()) { "Tried to seek block with $id, but it is outside of file's bounds (file size ${reader.length()} bytes, seeking ${id * blockSize + blocksOffsetStart})! (does not exist)" }
|
||||
reader.seek(id * blockSize + blocksOffsetStart)
|
||||
}
|
||||
|
||||
private inner class LeafInputStream(private var offset: Int) : InputStream() {
|
||||
private var canRead = true
|
||||
|
||||
override fun read(): Int {
|
||||
if (offset + 4 >= blockSize) {
|
||||
if (!seekNextBlock()) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
offset++
|
||||
return reader.read()
|
||||
}
|
||||
|
||||
override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||
Objects.checkFromIndexSize(off, len, b.size)
|
||||
var totalRead = 0
|
||||
var index = off
|
||||
|
||||
while (canRead && totalRead < len) {
|
||||
if (offset + 4 >= blockSize) {
|
||||
if (!seekNextBlock()) {
|
||||
return totalRead
|
||||
}
|
||||
}
|
||||
|
||||
val readAtMost = (blockSize - 4 - offset).coerceAtMost(len - totalRead)
|
||||
val readBytes = reader.read(b, index, readAtMost)
|
||||
|
||||
if (readBytes <= 0) {
|
||||
canRead = false
|
||||
break
|
||||
}
|
||||
|
||||
totalRead += readBytes
|
||||
index += readBytes
|
||||
offset += readBytes
|
||||
}
|
||||
|
||||
return totalRead
|
||||
}
|
||||
|
||||
private fun seekNextBlock(): Boolean {
|
||||
if (!canRead) {
|
||||
return false
|
||||
}
|
||||
|
||||
val nextBlockIndex = reader.readInt()
|
||||
|
||||
if (nextBlockIndex < 0L) {
|
||||
canRead = false
|
||||
return false
|
||||
}
|
||||
|
||||
seekBlock(nextBlockIndex.toLong())
|
||||
|
||||
check(readBlockType() == TreeBlockType.LEAF) { "Did not hit leaf block" }
|
||||
offset = 2
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,28 @@ fun RandomAccessFile.readVarIntInfo(): VarIntReadResult {
|
||||
return VarIntReadResult(result, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Читает Variable Length Integer как Int
|
||||
*/
|
||||
fun InputStream.readVarIntInfo(): VarIntReadResult {
|
||||
var result = 0
|
||||
var read = read()
|
||||
var i = 1
|
||||
|
||||
while (true) {
|
||||
result = (result shl 7) or (read and 0x7F)
|
||||
|
||||
if (read and 0x80 == 0) {
|
||||
break
|
||||
}
|
||||
|
||||
read = read()
|
||||
i++
|
||||
}
|
||||
|
||||
return VarIntReadResult(result, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Читает Variable Length Integer как Long
|
||||
*/
|
||||
|
@ -163,7 +163,10 @@ class StarboundPak(val path: File, callback: (finished: Boolean, status: String)
|
||||
// сразу за метаданными идёт количество файлов внутри данного pak в формате Big Endian variable int
|
||||
val indexNodeCount = reader.readVarLong()
|
||||
|
||||
private val indexNodes = HashMap<String, StarboundPakFile>()
|
||||
private val _indexNodes = HashMap<String, StarboundPakFile>()
|
||||
val indexNodes: Map<String, StarboundPakFile> = Collections.unmodifiableMap(_indexNodes)
|
||||
private val _indexNodesLowercase = HashMap<String, StarboundPakFile>()
|
||||
val indexNodesLowercase: Map<String, StarboundPakFile> = Collections.unmodifiableMap(_indexNodesLowercase)
|
||||
val root = StarboundPakDirectory("/")
|
||||
|
||||
init {
|
||||
@ -187,7 +190,10 @@ class StarboundPak(val path: File, callback: (finished: Boolean, status: String)
|
||||
throw IndexOutOfBoundsException("Garbage length at index $i: ${read.length}")
|
||||
}
|
||||
|
||||
indexNodes[read.name] = read
|
||||
_indexNodes[read.name] = read
|
||||
// Starbound игнорирует регистр букв когда ищет пути, даже внутри pak архивов
|
||||
_indexNodesLowercase[read.name.lowercase()] = read
|
||||
|
||||
root.resolve(read.directoryHiearchy).writeFile(read)
|
||||
|
||||
val last = read.name.substringAfterLast('/').substringAfterLast('.', "")
|
||||
@ -213,11 +219,11 @@ class StarboundPak(val path: File, callback: (finished: Boolean, status: String)
|
||||
}
|
||||
|
||||
override fun pathExists(path: String): Boolean {
|
||||
return indexNodes.containsKey(path)
|
||||
return _indexNodesLowercase.containsKey(path)
|
||||
}
|
||||
|
||||
override fun readOrNull(path: String): ByteBuffer? {
|
||||
val node = indexNodes[path] ?: return null
|
||||
val node = _indexNodesLowercase[path] ?: return null
|
||||
return node.read()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user