able to load player sprite from the disk archive

This commit is contained in:
minjaesong
2021-10-14 17:57:37 +09:00
parent c3b4dbc4b9
commit e679a421e5
9 changed files with 52 additions and 96 deletions

View File

@@ -12,6 +12,7 @@ The main game directory is composed of following directories:
[-2] spritedef,
[-3] optional spritedef-glow,
[-1025] sprite-bodypart-name-to-entry-number-map.properties,
[-1026] spriteglow-bodypart-name-to-entry-number-map.properties,
[1+] optional bodyparts tga.gz
}
*if file -1025 is not there, read bodyparts from assets directory

View File

@@ -1,37 +0,0 @@
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
SPRITESHEET=mods/basegame/sprites/test_werebeast/taimuglow_
EXTENSION=.tga
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
CONFIG=SIZE 64,98;ORIGINX 40
# note to self: don't implement skeleton hierarchy: there's too many exceptions
# besides, you have "ALL" key.
! a skeleton also defines what body parts (images) be used.
! you can also write multiline text using reverse solidus; this is a feature of .properties
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
! are painted first, and any object that comes before it will paint over it. In other words, this list is
! first reversed then being iterated.
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
# TODO right now accessory points are explicitly defined. Should they be injected in run-time?
SKELETON_STAND=HEADGEAR 0,32;\
ARM_REST_LEFT -8,49;HELD_ITEM -6,11;\
HEAD 2,83;\
TORSO_0 0,55;\
TORSO_1 0,55;\
LEG_REST_RIGHT -4,22;\
LEG_REST_LEFT 7,22;\
ARM_REST_RIGHT 11,51;\
TAIL_0 -11,27
# skeleton_stand is used for testing purpose
ANIM_RUN=DELAY 0.3;ROW 2;SKELETON SKELETON_STAND
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
ANIM_IDLE_1=TORSO_1 0,-999;HEAD 0,-1
ANIM_IDLE_2=TORSO_0 0,-999;ARM_REST_LEFT 0,1;ARM_REST_RIGHT 0,1

View File

@@ -1,37 +0,0 @@
# complete file name is: SPRITESHEET + bodypart name + EXTENSION
SPRITESHEET=mods/basegame/sprites/test_werebeast/taimu_
EXTENSION=.tga
# defines frame size and origin point. Origin point is given as: (originx, size.y - 1)
# ORIGINY is deduced from the sprite size as shown in above; you only need to set ORIGINX
CONFIG=SIZE 64,98;ORIGINX 40
# note to self: don't implement skeleton hierarchy: there's too many exceptions
# besides, you have "ALL" key.
! a skeleton also defines what body parts (images) be used.
! you can also write multiline text using reverse solidus; this is a feature of .properties
! skeleton joints are ordered: foremost-drawn object comes first, which means lowermost object IN THIS LIST
! are painted first, and any object that comes before it will paint over it. In other words, this list is
! first reversed then being iterated.
! Joints' original point is defined in the document sprite_joints.psd. It also has visual representations.
# TODO right now accessory points are explicitly defined. Should they be injected in run-time?
SKELETON_STAND=HEADGEAR 0,32;\
ARM_REST_LEFT -8,49;HELD_ITEM -6,11;\
HEAD 2,83;\
TORSO_0 0,55;\
TORSO_1 0,55;\
LEG_REST_RIGHT -4,22;\
LEG_REST_LEFT 7,22;\
ARM_REST_RIGHT 11,51;\
TAIL_0 -11,27
# skeleton_stand is used for testing purpose
ANIM_RUN=DELAY 0.3;ROW 2;SKELETON SKELETON_STAND
ANIM_RUN_1=LEG_REST_RIGHT 2,2;LEG_REST_LEFT -2,0;TAIL_0 1,0
ANIM_RUN_2=ALL 0,2;LEG_REST_RIGHT 0,-2;LEG_REST_LEFT 0,2;TAIL_0 -1,0
ANIM_RUN_3=LEG_REST_RIGHT -2,0;LEG_REST_LEFT 2,2;TAIL_0 -1,0
ANIM_RUN_4=ALL 0,2;LEG_REST_RIGHT 0,2;LEG_REST_LEFT 0,-2;TAIL_0 1,0
ANIM_IDLE=DELAY 2;ROW 1;SKELETON SKELETON_STAND
ANIM_IDLE_1=TORSO_1 0,-999;HEAD 0,-1
ANIM_IDLE_2=TORSO_0 0,-999;ARM_REST_LEFT 0,1;ARM_REST_RIGHT 0,1

View File

@@ -3,6 +3,7 @@ package net.torvald.spriteassembler
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.utils.GdxRuntimeException
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.linearSearch
import net.torvald.terrarum.serialise.Common
import net.torvald.terrarum.tvda.ByteArray64InputStream
@@ -22,7 +23,7 @@ import kotlin.collections.HashMap
*/
object AssembleSheetPixmap {
private fun drawAndGetCanvas(properties: ADProperties, fileGetter: (String) -> InputStream): Pixmap {
private fun drawAndGetCanvas(properties: ADProperties, fileGetter: (String) -> InputStream?): Pixmap {
val canvas = Pixmap(properties.cols * properties.frameWidth, properties.rows * properties.frameHeight, Pixmap.Format.RGBA8888)
canvas.blending = Pixmap.Blending.SourceOver
@@ -35,15 +36,21 @@ object AssembleSheetPixmap {
}
fun fromAssetsDir(properties: ADProperties) = drawAndGetCanvas(properties) { partName: String ->
Gdx.files.internal("assets/${properties.toFilename(partName)}").read()
val file = Gdx.files.internal("assets/${properties.toFilename(partName)}")
if (file.exists()) file.read() else null
}
fun fromVirtualDisk(disk: SimpleFileSystem, properties: ADProperties): Pixmap {
fun fromVirtualDisk(disk: SimpleFileSystem, entrynum: Long, properties: ADProperties): Pixmap {
val bodypartMapping = Properties()
bodypartMapping.load(ByteArray64Reader(disk.getFile(-1025L)!!.bytes, Common.CHARSET))
bodypartMapping.load(ByteArray64Reader(disk.getFile(entrynum)!!.bytes, Common.CHARSET))
val fileGetter = { partName: String ->
ByteArray64InputStream(disk.getFile(bodypartMapping[partName] as Long)!!.bytes)
bodypartMapping.getProperty(partName).let {
if (it != null)
ByteArray64InputStream(disk.getFile(bodypartMapping.getProperty(partName).toLong())!!.bytes)
else
null
}
}
return drawAndGetCanvas(properties, fileGetter)
@@ -52,19 +59,24 @@ object AssembleSheetPixmap {
private fun drawThisFrame(frameName: String,
canvas: Pixmap,
properties: ADProperties,
fileGetter: (String) -> InputStream
fileGetter: (String) -> InputStream?
) {
val theAnim = properties.getAnimByFrameName(frameName)
val skeleton = theAnim.skeleton.joints.reversed()
val transforms = properties.getTransform(frameName)
val bodypartOrigins = properties.bodyparts
val bodypartImages = properties.bodyparts.keys.map {
try {
val bytes = fileGetter(it).readAllBytes()
it to Pixmap(bytes, 0, bytes.size)
}
catch (e: GdxRuntimeException) {
it to null
val bodypartImages = properties.bodyparts.keys.map { partname ->
fileGetter(partname).let { file ->
if (file == null) partname to null
else {
try {
val bytes = file.readAllBytes()
partname to Pixmap(bytes, 0, bytes.size)
}
catch (e: GdxRuntimeException) {
partname to null
}
}
}
}.toMap()
val transformList = AssembleFrameBase.makeTransformList(skeleton, transforms)

View File

@@ -701,7 +701,7 @@ fun AppUpdateListOfSavegames() {
e.printStackTrace()
null
}
}.filter { it != null }.sortedByDescending { it!!.diskFile.lastModified() } as List<DiskSkimmer>).forEach {
}.filter { it != null }.sortedByDescending { it!!.getLastModifiedOfFirstFile() } as List<DiskSkimmer>).forEach {
println(it.diskFile.absolutePath)
it.rebuild() // disk skimmer was created without initialisation, so do it now
@@ -724,7 +724,7 @@ fun AppUpdateListOfSavegames() {
e.printStackTrace()
null
}
}.filter { it != null }.sortedByDescending { it!!.diskFile.lastModified() } as List<DiskSkimmer>).forEach {
}.filter { it != null }.sortedByDescending { it!!.getLastModifiedOfFirstFile() } as List<DiskSkimmer>).forEach {
println(it.diskFile.absolutePath)
it.rebuild() // disk skimmer was created without initialisation, so do it now

View File

@@ -87,9 +87,9 @@ class IngamePlayer : ActorHumanoid {
fun reassembleSprite(disk: SimpleFileSystem, sprite: SpriteAnimation?, spriteGlow: SpriteAnimation? = null) {
if (animDesc != null && sprite != null)
_rebuild(disk, animDesc!!, sprite)
_rebuild(disk, -1025L, animDesc!!, sprite)
if (animDescGlow != null && spriteGlow != null)
_rebuild(disk, animDescGlow!!, spriteGlow)
_rebuild(disk, -1026L, animDescGlow!!, spriteGlow)
}
private fun _rebuild(ad: ADProperties, sprite: SpriteAnimation) {
@@ -116,10 +116,10 @@ class IngamePlayer : ActorHumanoid {
sprite.nRows = newAnimDelays.size
}
private fun _rebuild(disk: SimpleFileSystem, ad: ADProperties, sprite: SpriteAnimation) {
private fun _rebuild(disk: SimpleFileSystem, entrynum: Long, ad: ADProperties, sprite: SpriteAnimation) {
// TODO injecting held item/armour pictures? Would it be AssembleSheetPixmap's job?
val pixmap = if (disk.getEntry(-1025) != null) AssembleSheetPixmap.fromVirtualDisk(disk, ad) else AssembleSheetPixmap.fromAssetsDir(ad)
val pixmap = if (disk.getEntry(entrynum) != null) AssembleSheetPixmap.fromVirtualDisk(disk, entrynum, ad) else AssembleSheetPixmap.fromAssetsDir(ad)
val texture = Texture(pixmap)
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
pixmap.dispose()

View File

@@ -222,8 +222,16 @@ class UILoadDemoSavefiles : UICanvas() {
if (mode == 2) {
loadFired += 1
// to hide the "flipped skybox" artefact
batch.end()
gdxClearAndSetBlend(.094f, .094f, .094f, 0f)
batch.begin()
batch.color = Color.WHITE
val txt = Lang["MENU_IO_LOADING"]
App.fontGame.draw(batch, txt, (App.scr.width - App.fontGame.getWidth(txt)) / 2f, (App.scr.height - App.fontGame.lineHeight) / 2f)
if (loadFired == 2) {
LoadSavegame(playerDisk!!, worldDisk)
}

View File

@@ -10,6 +10,7 @@ import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.WorldgenLoadScreen
import net.torvald.terrarum.modulebasegame.gameactors.PlayerBuilderTestSubject1
import net.torvald.terrarum.modulebasegame.gameactors.PlayerBuilderWerebeastTest
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.utils.RandomWordsName
@@ -39,7 +40,8 @@ class UIProxyNewRandomGame : UICanvas() {
val ingame = TerrarumIngame(App.batch)
val worldParam = TerrarumIngame.NewGameParams(
PlayerBuilderTestSubject1(),
// PlayerBuilderTestSubject1(),
PlayerBuilderWerebeastTest(),
TerrarumIngame.NewWorldParameters(2880, 1350, HQRNG().nextLong(), RandomWordsName(4))
)
// val worldParam = TerrarumIngame.NewWorldParameters(2880, 1350, 0x51621D)

View File

@@ -69,7 +69,7 @@ removefile:
*/
private var entryToOffsetTable = HashMap<EntryID, Long>()
lateinit var fa: RandomAccessFile//RandomAccessFile(diskFile, "rw")
val fa: RandomAccessFile = RandomAccessFile(diskFile, "rw")
private fun debugPrintln(s: Any) {
if (false) println(s.toString())
@@ -87,7 +87,7 @@ removefile:
fun rebuild() {
checkFileSanity() // state of the file may have been changed (e.g. file deleted) so we check again
fa = RandomAccessFile(diskFile, "rw")
// fa = RandomAccessFile(diskFile, "rw")
val fis = FileInputStream(diskFile)
var currentPosition = fis.skip(VirtualDisk.HEADER_SIZE) // skip disk header
@@ -353,6 +353,13 @@ removefile:
return bytes.toCanonicalString(charset)
}
fun getLastModifiedOfFirstFile(): Long {
val bytes = ByteArray(6)
fa.seek(326L)
fa.read(bytes)
return bytes.toInt48()
}
///////////////////////////////////////////////////////
// THESE ARE METHODS TO SUPPORT ON-LINE MODIFICATION //
///////////////////////////////////////////////////////