Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to dump textures from cache #6

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/kotlin/com/opennxt/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ object Constants {
val CACHE_PATH = DATA_PATH.resolve("cache")
val PROT_PATH = DATA_PATH.resolve("prot")
val RESOURCE_PATH = DATA_PATH.resolve("resources")
val TEXTURES_PATH_DXT = DATA_PATH.resolve("textures/dxt")
val TEXTURES_PATH_PNG = DATA_PATH.resolve("textures/png")
val TEXTURES_PATH_MIP = DATA_PATH.resolve("textures/mipmap")
val TEXTURES_PATH_ETC = DATA_PATH.resolve("textures/etc")
}
127 changes: 127 additions & 0 deletions src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package com.opennxt.tools.impl.other

import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.choice
import com.github.ajalt.clikt.parameters.types.int
import com.opennxt.Constants
import com.opennxt.filesystem.Container
import com.opennxt.tools.Tool
import io.netty.buffer.Unpooled
import java.io.ByteArrayInputStream
import java.io.File
import javax.imageio.ImageIO
import kotlin.system.exitProcess


class TextureDumper : Tool(name = "texture-dump", help = "This tool dumps textures from a user selected index.") {
private val idx: Int by option(help = "The index to dump from (default = -1 | all)").choice("dxt" to 52, "png" to 53, "mip" to 54, "etc" to 55, "all" to -1).default(-1)
private val textureId: Int by option("--tex", help = "The texture to dump (default = -1 | all)").int().default(-1)
override fun runTool() {
verifyTextureDirectories()

when {
(idx == -1 && textureId == -1) -> {

for (texIndex in 52..55) {
val table = filesystem.getReferenceTable(texIndex)!!
table.archives.forEach {
decodeTexture(texIndex, it.value.id)
}
}
}

(idx != -1 && textureId == -1) -> {

val table = filesystem.getReferenceTable(idx)!!
table.archives.forEach {
decodeTexture(idx, it.value.id)
}
}

(idx == -1 && textureId != -1) -> {

val texture = textureId
for (texIndex in 52..55) {
decodeTexture(texIndex, texture)
}
}

(idx != -1 && textureId != -1) -> {

val texture = textureId
decodeTexture(idx, texture)
}

else -> {
logger.error { "Invalid option found! | Index: $idx | Texture: $textureId" }
exitProcess(1)
}
}
}

private fun decodeTexture(index: Int, textureId: Int) {
if (!filesystem.exists(index, textureId)) {
logger.error { "No texture found! | Index: $index - Texture: $textureId | " +
"RANGE: ${filesystem.getReferenceTable(index)?.archives?.firstKey()} - " +
"${filesystem.getReferenceTable(index)?.archives?.lastKey()}" }
exitProcess(1)
}

val data = Unpooled.wrappedBuffer(Container.decode(filesystem.read(index, textureId)!!).data)
var raw = ByteArray(data.readableBytes())

if (index == 54 || index == 55) {
data.skipBytes(1)
} else {
data.skipBytes(5)
raw = ByteArray(data.readableBytes())
data.readBytes(raw)
}

when (index) {
52 -> {
File("${Constants.TEXTURES_PATH_DXT}/${textureId}.dds").writeBytes(raw)
}
53 -> {
val image = ImageIO.read(ByteArrayInputStream(raw))
ImageIO.write(image, "png", File("${Constants.TEXTURES_PATH_PNG}/${textureId}.png"))
}
54 -> {
for (level in 0 until data.readUnsignedByte().toInt()) {
val size = data.readInt()
raw = ByteArray(size)
data.readBytes(raw)

val image = ImageIO.read(ByteArrayInputStream(raw))
val file = File("${Constants.TEXTURES_PATH_MIP}/${textureId}/${image.width}x${image.height}.png").also {
it.parentFile.mkdirs()
}
ImageIO.write(image, "png", file)
}
}
55 -> {
val size = data.readInt()
raw = ByteArray(size)
data.readBytes(raw)
File("${Constants.TEXTURES_PATH_ETC}/${textureId}.ktx").writeBytes(raw)
}
else -> {
logger.error { "Invalid index found! | Index: $index | Texture: $textureId" }
exitProcess(1)
}
}
}

private fun verifyTextureDirectories() {
try {
File("${Constants.TEXTURES_PATH_DXT}").mkdirs()
File("${Constants.TEXTURES_PATH_PNG}").mkdirs()
File("${Constants.TEXTURES_PATH_MIP}").mkdirs()
File("${Constants.TEXTURES_PATH_ETC}").mkdirs()
} catch (e: SecurityException) {
logger.error { "Unable to create required directories!" }
exitProcess(1)
}
}
}