character import wip

This commit is contained in:
minjaesong
2023-08-25 00:24:12 +09:00
parent 8dda7ac79b
commit b1e45f1743
8 changed files with 195 additions and 21 deletions

View File

@@ -8,6 +8,7 @@
"GAME_ACTION_MOVE_VERB" : "Move",
"GAME_ACTION_ZOOM" : "Zoom",
"MENU_IO_AUTOSAVE": "Autosave",
"MENU_IO_CLEAR": "Clear",
"MENU_IO_IMPORT": "Import",
"MENU_IO_MANUAL_SAVE": "Manual Save",
"MENU_LABEL_COPYRIGHT": "Copyright",
@@ -16,6 +17,7 @@
"MENU_LABEL_IME": "IME",
"MENU_LABEL_IME_TOGGLE": "Toggle IME",
"MENU_LABEL_KEYBOARD_LAYOUT": "Keyboard Layout",
"MENU_LABEL_PASTE": "Paste",
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Clipboard",
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
"MENU_LABEL_RESET" : "Reset",

View File

@@ -8,6 +8,7 @@
"GAME_ACTION_MOVE_VERB" : "이동하기",
"GAME_ACTION_ZOOM" : "확대·축소",
"MENU_IO_AUTOSAVE": "자동 저장",
"MENU_IO_CLEAR": "지우기",
"MENU_IO_IMPORT": "가져오기",
"MENU_IO_MANUAL_SAVE": "수동 저장",
"MENU_LABEL_COPYRIGHT": "저작권",
@@ -16,6 +17,7 @@
"MENU_LABEL_IME": "입력기",
"MENU_LABEL_IME_TOGGLE": "입력기 켜고 끄기",
"MENU_LABEL_KEYBOARD_LAYOUT": "자판 배열",
"MENU_LABEL_PASTE": "붙여넣기",
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "복사한 텍스트 붙여넣기",
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
"MENU_LABEL_RESET" : "재설정",

View File

@@ -1,3 +1,5 @@
{
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "This is a world currently playing."
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "This is a world currently playing.",
"CONTEXT_IMPORT_AVATAR_INSTRUCTION_1": "Copy the Avatar Code into the clipboard, then hit the Paste button below.",
"CONTEXT_IMPORT_AVATAR_INSTRUCTION_2": ""
}

View File

@@ -1,3 +1,5 @@
{
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다."
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다.",
"CONTEXT_IMPORT_AVATAR_INSTRUCTION_1": "아바타 코드를 클립보드에 복사한 다음, 아래의 붙여넣기 버튼을 눌러주세요.",
"CONTEXT_IMPORT_AVATAR_INSTRUCTION_2": ""
}

View File

@@ -5,7 +5,7 @@
"cloudChance": 250,
"cloudGamma": [0.48, 1.8],
"cloudGammaVariance": [0.1, 0.1],
"windSpeed": 0.25,
"windSpeed": 10.25,
"windSpeedVariance": 1.0,
"clouds": {
"cumulonimbus": {

View File

@@ -0,0 +1,161 @@
package net.torvald.terrarum.modulebasegame.ui
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.App
import net.torvald.terrarum.Second
import net.torvald.terrarum.ceilToInt
import net.torvald.terrarum.gamecontroller.*
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.serialise.Ascii85Codec
import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarum.ui.UIItem
import net.torvald.terrarum.ui.UIItemTextButton
import net.torvald.terrarum.utils.Clipboard
/**
* Created by minjaesong on 2023-08-24.
*/
class UIImportAvatar(val remoCon: UIRemoCon) : Advanceable() {
override var width = 480 // SAVE_CELL_WIDTH
override var height = 480
override var openCloseTime: Second = OPENCLOSE_GENERIC
private val drawX = (Toolkit.drawWidth - width) / 2
private val drawY = (App.scr.height - height) / 2
private val cols = 80
private val rows = 30
private val goButtonWidth = 180
private val codeBox = UIItemCodeBox(this, (Toolkit.drawWidth - App.fontSmallNumbers.W * cols) / 2, drawY, cols, rows)
private val clearButton = UIItemTextButton(this,
{ Lang["MENU_IO_CLEAR"] }, drawX + (width/2 - goButtonWidth) / 2, drawY + height - 24 - 34, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
private val pasteButton = UIItemTextButton(this,
{ Lang["MENU_LABEL_PASTE"] }, drawX + width/2 + (width/2 - goButtonWidth) / 2, drawY + height - 24 - 34, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
private val backButton = UIItemTextButton(this,
{ Lang["MENU_LABEL_BACK"] }, drawX + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
private val goButton = UIItemTextButton(this,
{ Lang["MENU_IO_IMPORT"] }, drawX + width/2 + (width/2 - goButtonWidth) / 2, drawY + height - 24, goButtonWidth, alignment = UIItemTextButton.Companion.Alignment.CENTRE, hasBorder = true)
init {
addUIitem(codeBox)
addUIitem(clearButton)
addUIitem(pasteButton)
addUIitem(backButton)
addUIitem(goButton)
clearButton.clickOnceListener = { _,_ ->
codeBox.clearTextBuffer()
}
pasteButton.clickOnceListener = { _,_ ->
codeBox.pasteFromClipboard()
}
backButton.clickOnceListener = { _,_ ->
remoCon.openUI(UILoadSavegame(remoCon))
}
goButton.clickOnceListener = { _,_ ->
doImport()
}
}
override fun updateUI(delta: Float) {
uiItems.forEach { it.update(delta) }
}
override fun renderUI(batch: SpriteBatch, camera: Camera) {
uiItems.forEach { it.render(batch, camera) }
}
override fun dispose() {
}
override fun advanceMode(button: UIItem) {
}
private fun doImport() {
val rawStr = codeBox.textBuffer.toString()
// sanity check
val ascii85codec = Ascii85Codec((33..117).map { it.toChar() }.joinToString(""))
val ascii85str = rawStr.substring(2 until rawStr.length - 2).replace("z", "!!!!!")
}
}
class UIItemCodeBox(parent: UIImportAvatar, initialX: Int, initialY: Int, val cols: Int = 80, val rows: Int = 24) : UIItem(parent, initialX, initialY) {
override val width = App.fontSmallNumbers.W * cols
override val height = App.fontSmallNumbers.H * rows
override fun dispose() {
}
private var highlightCol: Color = Toolkit.Theme.COL_INACTIVE
var selected = false
private var textCursorPosition = 0
internal var textBuffer = StringBuilder()
fun pasteFromClipboard() {
textBuffer.clear()
Clipboard.fetch().forEach {
if (it.code in 33..122) textBuffer.append(it)
}
textCursorPosition += textBuffer.length
}
override fun update(delta: Float) {
super.update(delta)
// if (!selected && mousePushed)
// selected = true
// else if (selected && mouseDown && !mouseUp)
// selected = false
if (textBuffer.isEmpty() && (Gdx.input.isKeyJustPressed(Input.Keys.V) && (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)))) {
pasteFromClipboard()
}
}
override fun render(batch: SpriteBatch, camera: Camera) {
// draw box backgrounds
batch.color = UIInventoryFull.CELL_COL
Toolkit.fillArea(batch, posX, posY, width, height)
// draw borders
batch.color = if (selected) Toolkit.Theme.COL_SELECTED else if (mouseUp) Toolkit.Theme.COL_MOUSE_UP else Toolkit.Theme.COL_INACTIVE
Toolkit.drawBoxBorder(batch, posX - 1, posY - 1, width + 2, height + 2)
// draw texts
if (textBuffer.isEmpty()) {
batch.color = Toolkit.Theme.COL_INACTIVE
App.fontGame.draw(batch, Lang["CONTEXT_IMPORT_AVATAR_INSTRUCTION_1"], posX + 5, posY)
App.fontGame.draw(batch, Lang["CONTEXT_IMPORT_AVATAR_INSTRUCTION_2"], posX + 5f, posY + App.fontGame.lineHeight)
}
else {
batch.color = Color.WHITE
val scroll = ((textBuffer.length.toDouble() / cols).ceilToInt() - rows).coerceAtLeast(0)
for (i in scroll * cols until textBuffer.length) {
val c = textBuffer[i]
val x = ((i - scroll * cols) % cols) * App.fontSmallNumbers.W.toFloat()
val y = ((i - scroll * cols) / cols) * App.fontSmallNumbers.H.toFloat()
App.fontSmallNumbers.draw(batch, "$c", posX + x, posY + y)
}
}
}
fun clearTextBuffer() {
textBuffer.clear()
textCursorPosition = 0
}
}

View File

@@ -41,7 +41,7 @@ object UITitleRemoConYaml {
// todo add MENU_IO_IMPORT
val injectedMenuSingleCharSel = """
- MENU_IO_IMPORT
- MENU_IO_IMPORT : net.torvald.terrarum.modulebasegame.ui.UIImportAvatar
- CONTEXT_CHARACTER_NEW : net.torvald.terrarum.modulebasegame.ui.UINewCharacter
- MENU_LABEL_RETURN
"""

View File

@@ -4,27 +4,26 @@ import net.torvald.terrarum.savegame.toBigEndian
import java.util.UUID
import kotlin.math.ceil
/**
* Ascii85 implementation with my own character table based on RFC 1924. Will NOT truncate '00000' into something else;
* just gzip the inputstream instead!
/** My own string set that:
* - no "/": avoids nonstandard JSON comment key which GDX will happily parse away
* - no "\": you know what I mean\\intention
* - no "$": avoids Kotlin string template
* - no "[{]},": even the dumbest parser can comprehend the output
*/
object Ascii85 {
/** My own string set that:
* - no "/": avoids nonstandard JSON comment key which GDX will happily parse away
* - no "\": you know what I mean\\intention
* - no "$": avoids Kotlin string template
* - no "[{]},": even the dumbest parser can comprehend the output
*/
private const val CHAR_TABLE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#%&'()*+-.:;<=>?@^_`|~"
open class Ascii85Codec(private val CHAR_TABLE: String = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#%&'()*+-.:;<=>?@^_`|~") {
init {
if (CHAR_TABLE.length != 85) throw IllegalArgumentException("CHAR_TABLE is not 85 chars long")
}
/** As per Adobe standard */
//private val CHAR_TABLE = (33 until (33+85)).toList().map { it.toChar() }.joinToString("") // testing only!
private val INVERSE_TABLE = LongArray(127)
/** Int of `-1` */
const val PAD_BYTE = -1
val PAD_BYTE = -1
/** Null-character (`\0`) */
const val PAD_CHAR = 0.toChar()
val PAD_CHAR = 0.toChar()
private val INTERNAL_PAD_BYTE = 0
private val INTERNAL_PAD_CHAR = CHAR_TABLE.last()
@@ -97,10 +96,10 @@ object Ascii85 {
}
val sum = (INVERSE_TABLE[s1.toInt()] * 52200625) +
(INVERSE_TABLE[s2.toInt()] * 614125) +
(INVERSE_TABLE[s3.toInt()] * 7225) +
(INVERSE_TABLE[s4.toInt()] * 85) +
INVERSE_TABLE[s5.toInt()]
(INVERSE_TABLE[s2.toInt()] * 614125) +
(INVERSE_TABLE[s3.toInt()] * 7225) +
(INVERSE_TABLE[s4.toInt()] * 85) +
INVERSE_TABLE[s5.toInt()]
return ByteArray(4 - padLen) { sum.ushr((3 - it) * 8).and(255).toByte() }
}
@@ -137,6 +136,12 @@ object Ascii85 {
}
}
/**
* Ascii85 implementation with my own character table based on RFC 1924. Will NOT truncate '00000' into something else;
* just gzip the inputstream instead!
*/
object Ascii85 : Ascii85Codec()
fun UUID.toAscii85() =
Ascii85.encodeBytes(this.mostSignificantBits.toBigEndian() + this.leastSignificantBits.toBigEndian())
fun String.ascii85toUUID(): UUID {