diff --git a/src/net/torvald/terrarum/gamecontroller/InputStrober.kt b/src/net/torvald/terrarum/gamecontroller/InputStrober.kt index decfe425d..13aa75584 100644 --- a/src/net/torvald/terrarum/gamecontroller/InputStrober.kt +++ b/src/net/torvald/terrarum/gamecontroller/InputStrober.kt @@ -159,9 +159,12 @@ object InputStrober { data class TerrarumKeyboardEvent( val type: Int, - val character: String, // representative key symbol - val headkey: Int, // representative keycode + /** representative key symbol */ + val character: String, + /** representative keycode */ + val headkey: Int, val repeatCount: Int, + /** always fixed size of 8 elements */ val keycodes: IntArray ) diff --git a/src/net/torvald/terrarum/modulebasegame/ui/UIRedeemCodeMachine.kt b/src/net/torvald/terrarum/modulebasegame/ui/UIRedeemCodeMachine.kt index 17d4f36fd..471a2c6f4 100644 --- a/src/net/torvald/terrarum/modulebasegame/ui/UIRedeemCodeMachine.kt +++ b/src/net/torvald/terrarum/modulebasegame/ui/UIRedeemCodeMachine.kt @@ -8,6 +8,7 @@ import net.torvald.terrarum.App import net.torvald.terrarum.ControlPresets import net.torvald.terrarum.INGAME import net.torvald.terrarum.RunningEnvironment +import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.ui.* import net.torvald.unicode.getKeycapPC @@ -54,6 +55,27 @@ class UIRedeemCodeMachine : UICanvas( private val thisOffsetX = UIInventoryFull.INVENTORY_CELLS_OFFSET_X() + UIItemInventoryElemSimple.height + UIItemInventoryItemGrid.listGap - halfSlotOffset private val yEnd = -UIInventoryFull.YPOS_CORRECTION + (App.scr.height + UIInventoryFull.internalHeight).div(2).toFloat() + private val alphnums = (('0'..'9') + ('a'..'z') + ('A'..'Z')).map { "$it" }.toHashSet() + + override fun inputStrobed(e: TerrarumKeyboardEvent) { + super.inputStrobed(e) + + if (alphnums.contains(e.character)) { + inputPanel.acceptChar(e.character[0].uppercaseChar()) + } + else if (e.keycodes[0] == Input.Keys.BACKSPACE && e.keycodes[1] == 0) { + inputPanel.backspace() + } + else if (e.keycodes[0] == Input.Keys.FORWARD_DEL && e.keycodes[1] == 0) { + inputPanel.reverseBackspace() + } + else if (e.keycodes[0] == Input.Keys.LEFT && e.keycodes[1] == 0) { + inputPanel.__moveCursorBackward(1) + } + else if (e.keycodes[0] == Input.Keys.RIGHT && e.keycodes[1] == 0) { + inputPanel.__moveCursorForward(1) + } + } override fun renderImpl(frameDelta: Float, batch: SpriteBatch, camera: OrthographicCamera) { UIInventoryFull.drawBackground(batch, 1f) diff --git a/src/net/torvald/terrarum/ui/UIItemRedeemCodeArea.kt b/src/net/torvald/terrarum/ui/UIItemRedeemCodeArea.kt index 60b77d0fb..227074e79 100644 --- a/src/net/torvald/terrarum/ui/UIItemRedeemCodeArea.kt +++ b/src/net/torvald/terrarum/ui/UIItemRedeemCodeArea.kt @@ -43,10 +43,15 @@ class UIItemRedeemCodeArea( private val inputText = StringBuilder(textCols * textRows) + private fun ensureLength() { + inputText.append(" ".repeat((textCols * textRows) - inputText.length + 1)) + inputText.setLength(textCols * textRows) + } private var textCaret = 0 fun clearInput() { inputText.clear(); textCaret = 0 } fun acceptChar(char: Char): Boolean { if (textCaret in 0 until textCols * textRows) { + ensureLength() inputText.insert(textCaret, char) textCaret++ return true @@ -54,25 +59,27 @@ class UIItemRedeemCodeArea( else return false } fun backspace(): Boolean { - if (textCaret in 1 until textCols * textRows) { + if (textCaret in 1 .. textCols * textRows) { inputText.deleteCharAt(textCaret - 1) + ensureLength() textCaret-- return true } else return false } fun reverseBackspace(): Boolean { - if (textCaret in 0 until (textCols * textRows - 1)) { + if (textCaret in 0 .. (textCols * textRows - 1)) { inputText.deleteCharAt(textCaret) + ensureLength() return true } else return false } fun __moveCursorBackward(delta: Int = 1) { - textCaret = (textCaret - 1).coerceIn(0, textCols * textRows) + textCaret = (textCaret - 1).coerceIn(0, textCols * textRows - 1) } fun __moveCursorForward(delta: Int = 1) { - textCaret = (textCaret + 1).coerceIn(0, textCols * textRows) + textCaret = (textCaret + 1).coerceIn(0, textCols * textRows - 1) } fun getInputAsString() = inputText.toString() @@ -117,7 +124,7 @@ class UIItemRedeemCodeArea( for (x in 0 until textCols) { BigAlphNum.draw( batch, - "${inputText.getOrElse(y * textRows + x) { ' ' }}", + "${inputText.getOrElse(y * textCols + x) { ' ' }}", posX + CELL_W * x + 2f, posY + CELL_H * y + 4f ) @@ -127,8 +134,8 @@ class UIItemRedeemCodeArea( // draw caret if (cursorBlinkTimer < 0.5f) { batch.color = caretCol - val cx = textCaret % textCols - val cy = textCaret / textCols + val cx = if (textCaret >= textCols * textRows) textCols else textCaret % textCols + val cy = if (textCaret >= textCols * textRows) textRows - 1 else textCaret / textCols Toolkit.drawStraightLine( batch, posX + CELL_W * cx - 1, diff --git a/src/net/torvald/terrarum/utils/BloomFilter.kt b/src/net/torvald/terrarum/utils/BloomFilter.kt new file mode 100644 index 000000000..81cf44b6f --- /dev/null +++ b/src/net/torvald/terrarum/utils/BloomFilter.kt @@ -0,0 +1,87 @@ +package net.torvald.terrarum.utils + +import java.math.BigInteger +import java.nio.ByteBuffer +import java.security.MessageDigest +import java.security.NoSuchAlgorithmException + +/** + * Created by minjaesong on 2023-02-05. + */ +class BloomFilter(capacity: Int, k: Int) { + private var set: ByteArray + + private var keySize = 0 + private var setSize: Int = 0 + + private var empty = true + + private var md: MessageDigest? = null + + init { + setSize = capacity + set = ByteArray(setSize) + keySize = k + empty = true + md = try { + MessageDigest.getInstance("MD5") + } + catch (e: NoSuchAlgorithmException) { + throw IllegalArgumentException("Error : MD5 Hash not found") + } + } + + fun makeEmpty() { + set = ByteArray(setSize) + empty = true + md = try { + MessageDigest.getInstance("MD5") + } + catch (e: NoSuchAlgorithmException) { + throw IllegalArgumentException("Error : MD5 Hash not found") + } + } + + fun restoreFromByteArray(oldSet: ByteArray) { + if (this.set.size != oldSet.size) + throw IllegalStateException("Cannot restore from bytes: expected ${this.set.size} byte-set, got ${oldSet.size} instead") + + this.set = oldSet + + empty = set.all { it == 0.toByte() } + } + + fun isEmpty() = empty + + private fun getHash(i: Int): Int { + md!!.reset() + val bytes: ByteArray = ByteBuffer.allocate(4).putInt(i).array() + md!!.update(bytes, 0, bytes.size) + return Math.abs(BigInteger(1, md!!.digest()).toInt()) % (set.size - 1) + } + + fun add(obj: Int) { + val tmpset = getSetArray(obj) + for (i in tmpset) set[i] = 1 + empty = false + } + + operator fun contains(obj: Int): Boolean { + val tmpset = getSetArray(obj) + for (i in tmpset) if (set[i].toInt() != 1) return false + return true + } + + private fun getSetArray(obj: Int): IntArray { + val tmpset = IntArray(keySize) + tmpset[0] = getHash(obj) + for (i in 1 until keySize) tmpset[i] = getHash(tmpset[i - 1]) + return tmpset + } + + fun serialise(): ByteArray { + val returningSet = ByteArray(setSize) + System.arraycopy(set, 0, returningSet, 0, setSize) + return returningSet + } +} \ No newline at end of file diff --git a/work_files/DataFormats/SAVE_FORMAT.md b/work_files/DataFormats/SAVE_FORMAT.md index 41b10fe24..46bf5a0ad 100644 --- a/work_files/DataFormats/SAVE_FORMAT.md +++ b/work_files/DataFormats/SAVE_FORMAT.md @@ -15,6 +15,8 @@ The main game directory is composed of following directories: [-5] screenshot.tga.gz [-1025] !optional! sprite-bodypart-name-to-entry-number-map.properties, [-1026] !optional! spriteglow-bodypart-name-to-entry-number-map.properties, + /* -2147483648 and onward are for BLOBs */ + [-2147483648] Redeemed Codes Bloom Filter [1+] !optional! bodyparts tga.gz } *if file -1025 is not there, read bodyparts from assets directory