mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
character import wip
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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" : "재설정",
|
||||
|
||||
@@ -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": ""
|
||||
}
|
||||
@@ -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": ""
|
||||
}
|
||||
@@ -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": {
|
||||
|
||||
161
src/net/torvald/terrarum/modulebasegame/ui/UIImportAvatar.kt
Normal file
161
src/net/torvald/terrarum/modulebasegame/ui/UIImportAvatar.kt
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user