From 158eb7b63f9fd33481630c04cf47f82d290ec2e5 Mon Sep 17 00:00:00 2001
From: woahscam <elkin.austin@hotmail.com>
Date: Fri, 7 May 2021 02:37:36 -0400
Subject: [PATCH 1/3] Update constants to support texture dumper paths

---
 src/main/kotlin/com/opennxt/Constants.kt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/main/kotlin/com/opennxt/Constants.kt b/src/main/kotlin/com/opennxt/Constants.kt
index ab9faf9..e14122a 100644
--- a/src/main/kotlin/com/opennxt/Constants.kt
+++ b/src/main/kotlin/com/opennxt/Constants.kt
@@ -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")
 }
\ No newline at end of file

From dca4cdecf25552ddb680a6e00ec4ab4a24d53bc8 Mon Sep 17 00:00:00 2001
From: woahscam <elkin.austin@hotmail.com>
Date: Fri, 7 May 2021 02:38:33 -0400
Subject: [PATCH 2/3] Added ability to dump textures

---
 .../opennxt/tools/impl/other/TextureDumper.kt | 127 ++++++++++++++++++
 1 file changed, 127 insertions(+)
 create mode 100644 src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt

diff --git a/src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt b/src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt
new file mode 100644
index 0000000..77fb328
--- /dev/null
+++ b/src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt
@@ -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(901)
+            }
+        }
+    }
+
+    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(902)
+        }
+
+        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(903)
+            }
+        }
+    }
+
+    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(900)
+        }
+    }
+}
\ No newline at end of file

From 84b1cf53bce4955ebd72c77fc7a2700703b876ad Mon Sep 17 00:00:00 2001
From: woahscam <woahscam@hotmail.com>
Date: Fri, 7 May 2021 11:07:11 -0400
Subject: [PATCH 3/3] Minor compliance correction

---
 .../com/opennxt/tools/impl/other/TextureDumper.kt      | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt b/src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt
index 77fb328..cffdf5e 100644
--- a/src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt
+++ b/src/main/kotlin/com/opennxt/tools/impl/other/TextureDumper.kt
@@ -55,7 +55,7 @@ class TextureDumper : Tool(name = "texture-dump", help = "This tool dumps textur
 
             else -> {
                 logger.error { "Invalid option found! | Index: $idx | Texture: $textureId" }
-                exitProcess(901)
+                exitProcess(1)
             }
         }
     }
@@ -65,7 +65,7 @@ class TextureDumper : Tool(name = "texture-dump", help = "This tool dumps textur
             logger.error { "No texture found! | Index: $index - Texture: $textureId | " +
                     "RANGE: ${filesystem.getReferenceTable(index)?.archives?.firstKey()} - " +
                     "${filesystem.getReferenceTable(index)?.archives?.lastKey()}" }
-            exitProcess(902)
+            exitProcess(1)
         }
 
         val data = Unpooled.wrappedBuffer(Container.decode(filesystem.read(index, textureId)!!).data)
@@ -108,7 +108,7 @@ class TextureDumper : Tool(name = "texture-dump", help = "This tool dumps textur
             }
             else -> {
                 logger.error { "Invalid index found! | Index: $index | Texture: $textureId" }
-                exitProcess(903)
+                exitProcess(1)
             }
         }
     }
@@ -121,7 +121,7 @@ class TextureDumper : Tool(name = "texture-dump", help = "This tool dumps textur
             File("${Constants.TEXTURES_PATH_ETC}").mkdirs()
         } catch (e: SecurityException) {
             logger.error { "Unable to create required directories!" }
-            exitProcess(900)
+            exitProcess(1)
         }
     }
-}
\ No newline at end of file
+}