Implemented NPC spawn editing and lots of UI improvements

This commit is contained in:
ceikry 2023-03-11 15:17:57 -06:00
parent 5855afa6ca
commit 4b673c9063
98 changed files with 7040 additions and 3 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
build/
.idea/
.gradle/

View file

@ -1,5 +1,6 @@
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.4.32'
id 'application'
}
group 'org.example'
@ -11,12 +12,21 @@ repositories {
}
}
application {
mainClass = 'MainScreenKt'
}
dependencies {
implementation "org.jetbrains:markdown-jvm:0.2.0"
implementation "com.github.ajalt.mordant:mordant:2.0.0-alpha2"
implementation "com.github.weisj:darklaf-core:2.5.5"
implementation "com.googlecode.json-simple:json-simple:1.1.1"
implementation "org.jetbrains.kotlin:kotlin-stdlib"
// https://mvnrepository.com/artifact/com.displee/disio
implementation group: 'com.displee', name: 'disio', version: '2.2'
// https://mvnrepository.com/artifact/com.displee/rs-cache-library
implementation group: 'com.displee', name: 'rs-cache-library', version: '6.8.1'
}
task buildJar(type: Jar) {

View file

@ -8,7 +8,7 @@ object EditorConstants {
var CONFIG_PATH = ""
var VALID_FILES = arrayOf("drop_tables.json","npc_configs.json","item_configs.json", "shops.json", "object_configs.json")
var VALID_FILES = arrayOf("drop_tables.json","npc_configs.json","item_configs.json", "shops.json", "object_configs.json", "npc_spawns.json", "ground_item_spawns.json")
var CREDITS = arrayOf(
"weisJ - darklaf look and feel themes http://github.com/weisj",

View file

@ -1,6 +1,7 @@
import org.json.simple.JSONArray
import org.json.simple.JSONObject
import org.json.simple.parser.JSONParser
import tools.Util
import java.io.File
import java.io.FileReader
import java.io.FileWriter
@ -254,6 +255,66 @@ enum class Editors(val data: EditorData) {
e.printStackTrace()
}
}
}),
NPC_SPAWNS(object : EditorData("npc_spawns.json") {
override fun parse() {
Logger.logInfo("Parsing npc spawn data...")
val spawnMap = HashMap<Int, ArrayList<TableData.NPCSpawn>>()
configureParser()
data.forEach { spawnRaw ->
val spawn = spawnRaw as JSONObject
val id = spawn["npc_id"].toString().toInt()
val datas: Array<String> = spawn["loc_data"].toString().split("-".toRegex()).toTypedArray()
var tokens: Array<String>
for (d in datas) {
if(d.isEmpty()){
continue
}
tokens = d.replace("{", "").replace("}", "").split(",".toRegex()).toTypedArray()
val isWalks = tokens[3].trim { it <= ' ' } == "1"
val spawnDirection = Integer.valueOf(tokens[4].trim { it <= ' ' })
val spawnCoords = intArrayOf(Integer.valueOf(tokens[0].trim { it <= ' ' }), Integer.valueOf(tokens[1].trim { it <= ' ' }), Integer.valueOf(tokens[2].trim { it <= ' ' }))
val npc = TableData.NPCSpawn(id, TableData.Location(spawnCoords[0], spawnCoords[1], spawnCoords[2]), isWalks, spawnDirection)
val regionId = Util.getRegionId(npc.location)
if (!spawnMap.containsKey(regionId))
spawnMap[regionId] = ArrayList()
spawnMap[regionId]!!.add(npc)
}
}
TableData.npcSpawns = spawnMap
}
override fun save() {
Logger.logInfo("Saving NPC spawn info...")
val spawnMap = HashMap<Int, StringBuilder>()
for ((_, spawns) in TableData.npcSpawns) {
for (spawn in spawns) {
if (!spawnMap.contains(spawn.id)) spawnMap[spawn.id] = StringBuilder()
spawnMap[spawn.id]!!.append("{${spawn.location.x},${spawn.location.y},${spawn.location.z},${if(spawn.canWalk) 1 else 0},${spawn.spawnDirection}}-")
}
}
val spawnsJsonArray = JSONArray()
for ((id, spawnString) in spawnMap.entries.sortedBy { it.key.toInt() }) {
val spawn = JSONObject()
spawn["npc_id"] = id.toString()
spawn["loc_data"] = spawnString.toString()
spawnsJsonArray.add(spawn)
}
val manager = ScriptEngineManager()
val scriptEngine = manager.getEngineByName("JavaScript")
scriptEngine.put("jsonString", spawnsJsonArray.toJSONString())
scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)")
val prettyPrintedJson = scriptEngine["result"] as String
try {
FileWriter(EditorConstants.CONFIG_PATH + File.separator + fileName).use { file ->
file.write(prettyPrintedJson)
file.flush()
}
} catch (e: IOException) {
e.printStackTrace()
}
}
})
}

View file

@ -21,6 +21,7 @@ object MainScreen : JFrame("RS09 Thanos Tool ${EditorConstants.BUILD_NUMBER}") {
val openItem = JButton("Edit Item Configs")
val openShops = JButton("Edit Shops")
val openObjects = JButton("Edit Object Configs")
val openNpcItemSpawns = JButton("Edit NPC/Item Spawns")
var loadedModel = object : DefaultTableModel(){}
val loadedTable = object : JTable(loadedModel){
override fun editCellAt(p0: Int, p1: Int): Boolean {
@ -79,6 +80,10 @@ object MainScreen : JFrame("RS09 Thanos Tool ${EditorConstants.BUILD_NUMBER}") {
ShopList().open()
}
openNpcItemSpawns.addActionListener {
Rs2MapEditor.main(arrayOf())
}
val showCredits = JButton("Show Credits")
showCredits.addActionListener {
credits.isVisible = true
@ -87,8 +92,8 @@ object MainScreen : JFrame("RS09 Thanos Tool ${EditorConstants.BUILD_NUMBER}") {
val editorPanel = JPanel()
val selectionPanel = JPanel()
editorPanel.layout = BoxLayout(editorPanel, BoxLayout.Y_AXIS)//BoxLayout(editorPanel, BoxLayout.PAGE_AXIS)
for(i in arrayOf(openDrops, openNPC, openItem, openObjects, openShops, showCredits)){
editorPanel.layout = BoxLayout(editorPanel, BoxLayout.Y_AXIS)
for(i in arrayOf(openDrops, openNPC, openItem, openObjects, openShops, openNpcItemSpawns, showCredits)){
i.preferredSize = Dimension(175,40)
i.maximumSize = Dimension(175,40)
i.isEnabled = i == showCredits
@ -134,6 +139,7 @@ fun showLoaded(){
"item_configs" -> MainScreen.openItem.isEnabled = true.also { Editors.ITEM_CONFIGS.data.parse() }
"shops" -> MainScreen.openShops.isEnabled = true.also { Editors.SHOPS.data.parse() }
"object_configs" -> MainScreen.openObjects.isEnabled = true.also { Editors.OBJECT_CONFIGS.data.parse()}
"npc_spawns" -> MainScreen.openNpcItemSpawns.isEnabled = true.also { Editors.NPC_SPAWNS.data.parse() }
}
}
}

View file

@ -0,0 +1,97 @@
import java.awt.BorderLayout
import java.awt.Dimension
import java.awt.event.KeyEvent
import java.awt.event.KeyListener
import java.awt.event.MouseEvent
import java.awt.event.MouseListener
import java.util.*
import java.util.regex.PatternSyntaxException
import javax.swing.*
import javax.swing.table.DefaultTableCellRenderer
import javax.swing.table.DefaultTableModel
import javax.swing.table.TableRowSorter
object NPCMenu : JFrame("NPC Selection Menu") {
var model = DefaultTableModel()
var searchField = JTextField()
var sorter = TableRowSorter(model)
var cellRenderer = DefaultTableCellRenderer()
var populated = false
var caller: ((Int,String) -> Unit)? = null
private fun filter() {
var rf: RowFilter<DefaultTableModel?, Any?>? = null
//If current expression doesn't parse, don't update.
rf = try {
RowFilter.regexFilter("(?i)${searchField.text}")
} catch (e: PatternSyntaxException) {
return
}
sorter.rowFilter = rf
}
fun open() {
if (!populated) {
SwingUtilities.invokeLater {
for ((id,name) in TableData.npcNames) {
model.addRow(arrayOf(id,name))
}
isVisible = true
populated = true
}
} else {
isVisible = true
}
}
init {
layout = BorderLayout()
cellRenderer.toolTipText = "Double-Click to select."
val searchPanel = JPanel()
val searchLabel = JLabel("Search for NPC:")
searchField.preferredSize = Dimension(100, 20)
searchPanel.add(searchLabel)
searchPanel.add(searchField)
add(searchPanel, BorderLayout.NORTH)
setLocationRelativeTo(null)
val npcTable: JTable = object : JTable(model) {
override fun editCellAt(i: Int, i1: Int, eventObject: EventObject): Boolean {
return false
}
}
model.addColumn("ID")
model.addColumn("Name")
npcTable.rowSorter = sorter
npcTable.columnModel.getColumn(0).maxWidth = 55
npcTable.columnModel.getColumn(0).cellRenderer = cellRenderer
npcTable.columnModel.getColumn(1).cellRenderer = cellRenderer
npcTable.addMouseListener(object : MouseListener {
override fun mouseClicked(mouseEvent: MouseEvent) {
if (mouseEvent.clickCount == 2) {
val table = mouseEvent.source as JTable
val row = table.selectedRow
val selectedID = table.getValueAt(row,0).toString().toInt()
val selectedName = table.getValueAt(row,1).toString()
caller?.invoke(selectedID,selectedName)
isVisible = false
}
}
override fun mousePressed(mouseEvent: MouseEvent) {}
override fun mouseReleased(mouseEvent: MouseEvent) {}
override fun mouseEntered(mouseEvent: MouseEvent) {}
override fun mouseExited(mouseEvent: MouseEvent) {}
})
searchField.addKeyListener(object : KeyListener {
override fun keyTyped(keyEvent: KeyEvent) {
filter()
}
override fun keyPressed(keyEvent: KeyEvent) {}
override fun keyReleased(keyEvent: KeyEvent) {}
})
val scrollPane = JScrollPane(npcTable)
add(scrollPane, BorderLayout.SOUTH)
pack()
isVisible = false
}
}

View file

@ -0,0 +1,405 @@
import cacheops.cache.definition.data.OverlayDefinition
import cacheops.cache.definition.data.UnderlayDefinition
import cacheops.cache.definition.data.MapTile
import cacheops.cache.definition.decoder.*
import com.displee.cache.CacheLibrary
import const.Image.RED_DOT
import const.Image.YELLOW_DOT
import const.cachePath
import misc.CustomEventQueue
import tools.ItemSearchTool
import tools.NPCSearchTool
import tools.Util
import ui.*
import java.awt.*
import java.awt.event.*
import javax.swing.*
import javax.swing.border.*
import kotlin.system.exitProcess
object Rs2MapEditor {
val library = CacheLibrary.create(cachePath)
var region = 12850
var npcs = TableData.npcSpawns[region]
var items = GroundItemSpawnParser.parseItemSpawns(region)
var sceneries = TileSceneryParser.parseRegion(region)
val npcRows = ArrayList<NPCSpawnPanel.NPCRow>()
val itemRows = ArrayList<ItemSpawnPanel.ItemRow>()
var npcsUpdated = false
var itemsUpdated = false
var tileDataUpdated = false
var plane = 0
var visualizeHeight = false
var drawGrid = true
var previousHeight = -1
lateinit var mapPanel: MapPane
lateinit var npcPanel: NPCSpawnPanel
lateinit var itemPanel: ItemSpawnPanel
lateinit var infoPane: InfoPane
@JvmStatic
fun main(args: Array<String>) {
FloorUnderlayConfiguration.init()
FloorOverlayConfiguration.init()
MapTileParser.init()
underlayMap = FloorUnderlayConfiguration.floorUnderlays
overlayMap = FloorOverlayConfiguration.floorOverlays
MainFrame()
}
var cellX = 20
var cellY = 20
// Formatted points
var selectedPointX = 0
var selectedPointY = 0
get() = (64 - field) - 1
// Stores the underlay ID for each point
var colorPointMap: HashMap<Point, Int> = hashMapOf()
val componentPointMap = hashMapOf<Point, MapCell>()
// Stores the underlay ID with the Underlay Definition
lateinit var underlayMap: HashMap<Int, UnderlayDefinition>
lateinit var overlayMap: HashMap<Int, OverlayDefinition>
var selectedUnderlayId: Int? = null
var statusLabel = JLabel()
var infoLabel = JLabel()
var underlayInfo = JLabel("Right click a tile to get more information")
var underlayLabel = JLabel()
lateinit var npcIdInput: JTextField
lateinit var npcCanWalkCheckbox: JCheckBox
lateinit var npcDirectionCheckboxes: Array<JCheckBox>
lateinit var directionalCheckboxPanel: JPanel
lateinit var itemIdInput: JTextField
lateinit var itemRespawnInput: JTextField
lateinit var itemAmountInput: JTextField
lateinit var infoScrollPane: ScrollPane2
var state = EditorState.NONE
class MainFrame : JFrame("2009scape Map Viewer v1.0") {
init {
val statusBar = JPanel(FlowLayout(FlowLayout.LEFT))
statusBar.border = CompoundBorder(
LineBorder(Color.DARK_GRAY),
EmptyBorder(2, 3, 2, 3)
)
statusLabel.foreground = Color.YELLOW
directionalCheckboxPanel = JPanel(GridLayout(3,3))
npcDirectionCheckboxes = Array<JCheckBox>(8) { JCheckBox().also { it.addItemListener(DirectionCheckboxOnClick) } }
var cbCounter = 0
for (i in 0 until 9) {
if (i == 0) npcDirectionCheckboxes[i].setSelected(true)
if (i != 4) {
directionalCheckboxPanel.add(npcDirectionCheckboxes[cbCounter++])
} else {
directionalCheckboxPanel.add(JLabel("", SwingConstants.CENTER))
}
}
statusBar.add(statusLabel)
bounds = Rectangle(Dimension(1567, 850))
size.setSize(1567, 850)
maximumSize = Dimension(1567, 850)
defaultCloseOperation = HIDE_ON_CLOSE
jMenuBar = MenuBar()
mapPanel = MapPane()
npcIdInput = JTextField()
npcCanWalkCheckbox = JCheckBox()
itemIdInput = JTextField()
itemRespawnInput = JTextField()
itemAmountInput = JTextField()
npcPanel = NPCSpawnPanel()
itemPanel = ItemSpawnPanel()
infoPane = InfoPane()
infoScrollPane = ScrollPane2()
add(ScrollPane(), BorderLayout.CENTER)
add(infoScrollPane, BorderLayout.EAST)
add(statusBar, BorderLayout.SOUTH)
infoLabel.text = "Information"
statusLabel.text = "-"
setLocationRelativeTo(null)
isResizable = false
isVisible = true
CustomEventQueue.install()
}
}
class MapPane : JPanel() {
val gbc = GridBagConstraints()
val mapHeight = 64
val mapWidth = 64
init {
layout = GridBagLayout()
gbc.fill = GridBagConstraints.NONE
gbc.weightx = 1.0
SwingUtilities.invokeLater {
repaintMap()
}
}
fun repaintMap() {
colorPointMap.clear()
componentPointMap.clear()
this.removeAll()
for (row in 0 until mapHeight) {
for (column in 0 until mapWidth) {
gbc.gridx = column
gbc.gridy = row
var border: Border = MatteBorder(1, 1, if (row == mapHeight) 1 else 0, if (column == mapWidth) 1 else 0, Color(255,255,255,25))
val flippedY = (64 - row) - 1
val point = Point(column, flippedY)
colorPointMap[point] = MapTileParser.definition.getTile(column, flippedY, plane).underlayId - 1
val mapCell = MapCell()
val tileDef = MapTileParser.definition.getTile(column, flippedY, plane)
var overlayID = (MapTileParser.definition.getTile(column, flippedY, plane).overlayId - 1)
var underlayID = (MapTileParser.definition.getTile(column, flippedY, plane).underlayId - 1)
componentPointMap[point] = mapCell
add(mapCell, gbc)
if(overlayID < 0 && underlayID < 0){
mapCell.defaultBackground = Color(0,0,0,0)
mapCell.background = mapCell.defaultBackground
continue
}
if (underlayID < 0) {
underlayID = 0
}
if (overlayID < 0) {
overlayID = 0
}
val fluDef = underlayMap[underlayID]
val floDef = overlayMap[overlayID]
if (overlayID == 0) {
mapCell.background = fluDef!!.getRGB()
} else if (floDef!!.blendColor != -1) {
mapCell.background = Color(floDef.blendColor)
} else {
mapCell.background = floDef.getRGB()
}
if(visualizeHeight){
val height = tileDef.height
val otherTiles: List<MapTile> = Pair(column, flippedY).getSurroundingTiles()
val borderSizes = intArrayOf(0,0,0,0)
var borderColor = Color(0,0,0,0)
for(tileIndex in otherTiles.indices){
val tile = otherTiles[tileIndex]
if(height > tile.height){
val tileDiff = height - tile.height
val alpha = Math.min(tileDiff * 8, 255)
val color: Color
try {
color = Color(0,0,0, alpha)
} catch (e: Exception){
println("Invalid alpha value: $alpha")
return
}
val borderIndex = when(tileIndex){
0 -> 0
3 -> 1
2 -> 2
1 -> 3
else -> -1
}
borderSizes[borderIndex] = 3
if(color.alpha > borderColor.alpha) borderColor = color
}
}
mapCell.border = MatteBorder(borderSizes[0], borderSizes[1], borderSizes[2], borderSizes[3], borderColor)
} else if(drawGrid) {
mapCell.border = border
}
val sceneryHere = sceneries.filter { it.x == column && it.y == flippedY && it.plane == plane }.toList()
if(sceneryHere.isNotEmpty()){
sceneryHere.forEach(mapCell::flagScenery)
}
val thisAbsolute = Util.getAbsoluteCoordinates(region, column, flippedY, plane)
val npcsHere = npcs!!.filter { it.location == thisAbsolute }.toList()
if (npcsHere.isNotEmpty()) {
mapCell.layout = BorderLayout()
mapCell.add(JLabel(YELLOW_DOT))
}
val itemSpawnsHere = items.filter { it.x == column && it.y == flippedY && it.plane == plane }.toList()
if (itemSpawnsHere.isNotEmpty()) {
mapCell.layout = BorderLayout()
mapCell.add(JLabel(RED_DOT))
}
}
}
SwingUtilities.invokeLater {
this.repaint()
}
}
}
class ScrollPane : JPanel() {
init {
// Scroll bar
val scrollFrame = JScrollPane(mapPanel)
scrollFrame.maximumSize = Dimension(1300, 750)
scrollFrame.preferredSize = Dimension(1300, 750)
scrollFrame.verticalScrollBar.unitIncrement = 20
add(scrollFrame, BorderLayout.CENTER)
}
}
class ScrollPane2 : JPanel() {
lateinit var scrollFrame: JScrollPane
init {
// Scroll bar
layout = BorderLayout()
scrollFrame = JScrollPane(infoPane)
scrollFrame.preferredSize = Dimension(255, 980)
scrollFrame.verticalScrollBar.unitIncrement = 20
add(scrollFrame, BorderLayout.CENTER)
}
}
fun makeTextPanel(text: String?): JComponent {
val panel = JPanel(false)
val filler = JLabel(text)
filler.horizontalAlignment = JLabel.CENTER
panel.layout = GridLayout(1, 1)
panel.add(filler)
return panel
}
class MenuBar : JMenuBar() {
init {
add(GoMenuOption())
add(MoveRegionButton("NORTH", 0, 1))
add(MoveRegionButton("SOUTH", 0, -1))
add(MoveRegionButton("EAST", 1, 0))
add(MoveRegionButton("WEST", -1, 0))
add(JSeparator(JSeparator.VERTICAL))
add(JLabel("Plane: "))
add(PlaneButton(0))
add(PlaneButton(1))
add(PlaneButton(2))
add(PlaneButton(3))
}
}
class GoMenuOption : JMenu("Go..") {
init {
add(LoadRegionItem())
add(LoadByCoordinatesItem())
}
}
class LoadRegionItem : JMenuItem("To Region") {
init {
addActionListener {
val region = JOptionPane.showInputDialog("Enter Desired Region ID")
val regionId = region.toIntOrNull() ?: JOptionPane.showInputDialog("Invalid Integer Entered").toIntOrNull() ?: return@addActionListener
Rs2MapEditor.loadRegion(regionId)
}
}
}
class LoadByCoordinatesItem : JMenuItem("To Coords") {
init {
addActionListener {
val coords = JOptionPane.showInputDialog("Enter Coords")
val components = coords.split(",").map { it.trim { it <= ' ' }.toInt() }.toIntArray()
val regionId = Util.getRegionId (TableData.Location(components[0], components[1], components[2]))
Rs2MapEditor.loadRegion(regionId)
}
}
}
class PrefMenuOption : JMenu("Preferences") {
init {
add(visualizeHeightItem())
}
}
class visualizeHeightItem : JCheckBoxMenuItem("Visualize Heights", false) {
init {
addActionListener {
Rs2MapEditor.visualizeHeight = !Rs2MapEditor.visualizeHeight
SwingUtilities.invokeLater {
mapPanel.repaintMap()
}
}
}
}
class MoveRegionButton(symbol: String, val diffX: Int, val diffY: Int) : JButton(symbol) {
init {
this.addMouseListener (object : MouseAdapter() {
override fun mouseClicked (e: MouseEvent) {
var currentRegion = Rs2MapEditor.region
var newRegion = Util.getRegion(currentRegion, diffX, diffY)
Rs2MapEditor.loadRegion(newRegion)
}
})
}
}
var DirectionCheckboxOnClick = object : ItemListener {
override fun itemStateChanged (e: ItemEvent) {
var source = e.getItemSelectable()
if (source !is JCheckBox) return
if (e.getStateChange() == ItemEvent.SELECTED) {
for (checkbox in npcDirectionCheckboxes) { if (checkbox != source) checkbox.setSelected(false) }
} else {
var anySelected = false
for (checkbox in npcDirectionCheckboxes) { if (checkbox.isSelected) anySelected = true }
if (!anySelected) source.setSelected(true)
}
}
}
fun loadRegion (regionId: Int) {
Rs2MapEditor.region = regionId
Rs2MapEditor.plane = 0
npcs = TableData.npcSpawns[regionId] ?: ArrayList<TableData.NPCSpawn>().also { TableData.npcSpawns[regionId] = it }
items = GroundItemSpawnParser.parseItemSpawns(regionId)
sceneries = TileSceneryParser.parseRegion(regionId)
npcPanel.redrawRows()
itemPanel.redrawRows()
try {
MapTileParser.init()
mapPanel.repaintMap()
} catch (e: Exception){
mapPanel.removeAll()
mapPanel.revalidate()
JOptionPane.showMessageDialog(null, "No Map Data for Region ID $regionId.")
}
}
}
enum class EditorState{
NONE,
SET_UNDERLAY,
SET_OVERLAY,
ADD_NPC,
ADD_GROUNDITEM,
DEL_NPC,
DEL_GROUNDITEM
}

View file

@ -1,5 +1,6 @@
import org.json.simple.JSONArray
import org.json.simple.JSONObject
import tools.Util
import java.io.File
import java.io.FileWriter
import java.io.IOException
@ -8,11 +9,18 @@ import javax.script.ScriptEngineManager
object TableData {
class Shop(var id: Int,var title: String,var stock: ArrayList<Item>,var npcs: String,var currency: Int,var general_store: Boolean,var high_alch: Boolean,var forceShared: Boolean)
data class NPCSpawn(var id: Int, var location: Location, var canWalk: Boolean, var spawnDirection: Int)
data class ItemSpawn(var id: Int, var location: Location, var respawnTicks: Int, var amount: Int)
data class Location(val x: Int, val y: Int, val z: Int) {
val localCoords = Util.getRegionCoordinates(this)
}
val tables = ArrayList<NPCDropTable>()
val itemNames = hashMapOf<Int,String>()
val npcNames = hashMapOf<Int,String>()
val npcConfigKeys = HashSet<String>()
val npcConfigs = ArrayList<JSONObject>()
var npcSpawns = HashMap<Int, ArrayList<NPCSpawn>>()
val itemSpawns = HashMap<Int, ArrayList<ItemSpawn>>()
val objConfigKeys = HashSet<String>()
val objConfigs = ArrayList<JSONObject>()
var itemConfigKeys = HashSet<String>()

40
src/main/kotlin/cacheops/cache/Cache.kt vendored Normal file
View file

@ -0,0 +1,40 @@
package cacheops.cache
import com.displee.cache.index.Index255
import java.math.BigInteger
interface Cache {
var index255: Index255?
fun getFile(index: Int, archive: Int, file: Int = 0, xtea: IntArray? = null): ByteArray?
fun getFile(index: Int, name: String, xtea: IntArray? = null): ByteArray?
fun getArchive(indexId: Int, archiveId: Int): ByteArray?
fun generateOldVersionTable(): ByteArray
fun generateNewVersionTable(exponent: BigInteger, modulus: BigInteger): ByteArray
fun close()
fun getIndexCrc(indexId: Int): Int
fun archiveCount(indexId: Int, archiveId: Int): Int
fun lastFileId(indexId: Int, archive: Int): Int
fun lastArchiveId(indexId: Int): Int
fun getArchiveId(index: Int, name: String): Int
fun getArchiveId(index: Int, archive: Int): Int
fun getArchives(index: Int): IntArray
fun write(index: Int, archive: Int, file: Int, data: ByteArray, xteas: IntArray? = null)
fun update(): Boolean
}

View file

@ -0,0 +1,88 @@
package cacheops.cache
import com.displee.cache.CacheLibrary
import com.displee.cache.index.Index255
import java.math.BigInteger
class CacheDelegate(directory: String) : Cache {
private val delegate = CacheLibrary(directory)
init {
println("Cache read from $directory")
}
override var index255: Index255?
get() = delegate.index255
set(value) {
delegate.index255 = value
}
override fun getFile(index: Int, archive: Int, file: Int, xtea: IntArray?) =
delegate.data(index, archive, file, xtea)
override fun getFile(index: Int, name: String, xtea: IntArray?) = delegate.data(index, name, xtea)
override fun getArchive(indexId: Int, archiveId: Int): ByteArray? {
val index = if (indexId == 255) index255 else delegate.index(indexId)
if (index == null) {
println("Unable to find valid index for file request [indexId=$indexId, archiveId=$archiveId]}")
return null
}
val archiveSector = index.readArchiveSector(archiveId)
if (archiveSector == null) {
println("Unable to read archive sector $archiveId in index $indexId")
return null
}
return archiveSector.data
}
override fun generateOldVersionTable(): ByteArray = delegate.generateOldUkeys()
override fun generateNewVersionTable(exponent: BigInteger, modulus: BigInteger) = delegate.generateNewUkeys(exponent, modulus)
override fun close() = delegate.close()
override fun getIndexCrc(indexId: Int): Int {
return delegate.index(indexId).crc
}
override fun archiveCount(indexId: Int, archiveId: Int): Int {
return delegate.index(indexId).archive(archiveId)?.fileIds()?.size ?: 0
}
override fun lastFileId(indexId: Int, archive: Int): Int {
return delegate.index(indexId).archive(archive)?.last()?.id ?: -1
}
override fun lastArchiveId(indexId: Int): Int {
return delegate.index(indexId).last()?.id ?: 0
}
override fun getArchiveId(index: Int, name: String): Int {
return delegate.index(index).archiveId(name)
}
override fun getArchiveId(index: Int, hash: Int): Int {
delegate.index(index).archives().forEach { archive ->
if(archive.hashName == hash) {
return archive.id
}
}
return -1
}
override fun getArchives(index: Int): IntArray {
return delegate.index(index).archiveIds()
}
override fun write(index: Int, archive: Int, file: Int, data: ByteArray, xteas: IntArray?) {
delegate.put(index, archive, file, data, xteas)
}
override fun update(): Boolean {
delegate.update()
return true
}
}

View file

@ -0,0 +1,5 @@
package cacheops.cache
interface Definition {
var id: Int
}

View file

@ -0,0 +1,131 @@
package cacheops.cache
import cacheops.cache.buffer.read.BufferReader
import cacheops.cache.buffer.read.Reader
import java.util.concurrent.ConcurrentHashMap
abstract class DefinitionDecoder<T : Definition>(protected val cache: Cache, internal val index: Int) {
protected val dataCache = ConcurrentHashMap<Int, T>()
open val last: Int
get() = cache.lastArchiveId(index) * 256 + (cache.archiveCount(index, cache.lastArchiveId(index)))
val indices: IntRange
get() = 0..last
fun getOrNull(id: Int): T? {
var value = dataCache[id]
if (value == null) {
value = readData(id)
if (value != null) {
dataCache[id] = value
}
}
return value
}
open fun get(id: Int) = getOrNull(id) ?: create()
protected abstract fun create(): T
protected open fun getData(archive: Int, file: Int): ByteArray? {
return cache.getFile(index, archive, file)
}
protected open fun readData(id: Int): T? {
val archive = getArchive(id)
val file = getFile(id)
val data = getData(archive, file)
if (data != null) {
val definition = create()
definition.id = id
readLoop(definition, BufferReader(data))
definition.changeValues()
return definition
}
return null
}
protected open fun readLoop(definition: T, buffer: Reader) {
while (true) {
val opcode = buffer.readUnsignedByte()
if (opcode == 0) {
break
}
definition.read(opcode, buffer)
}
}
open fun getFile(id: Int) = id
open fun getArchive(id: Int) = id
protected abstract fun T.read(opcode: Int, buffer: Reader)
protected open fun T.changeValues() {
}
open fun clear() {
dataCache.clear()
}
fun forEach(function: (T) -> Unit) {
for (i in indices) {
val def = getOrNull(i) ?: continue
function.invoke(def)
}
}
companion object {
fun byteToChar(b: Byte): Char {
var i = 0xff and b.toInt()
require(i != 0) { "Non cp1252 character 0x" + i.toString(16) + " provided" }
if (i in 128..159) {
var char = UNICODE_TABLE[i - 128].toInt()
if (char == 0) {
char = 63
}
i = char
}
return i.toChar()
}
private var UNICODE_TABLE = charArrayOf(
'\u20ac',
'\u0000',
'\u201a',
'\u0192',
'\u201e',
'\u2026',
'\u2020',
'\u2021',
'\u02c6',
'\u2030',
'\u0160',
'\u2039',
'\u0152',
'\u0000',
'\u017d',
'\u0000',
'\u0000',
'\u2018',
'\u2019',
'\u201c',
'\u201d',
'\u2022',
'\u2013',
'\u2014',
'\u02dc',
'\u2122',
'\u0161',
'\u203a',
'\u0153',
'\u0000',
'\u017e',
'\u0178'
)
}
}

View file

@ -0,0 +1,7 @@
package cacheops.cache
import cacheops.cache.buffer.write.Writer
interface DefinitionEncoder<T : Definition> {
fun Writer.encode(definition: T)
}

View file

@ -0,0 +1,223 @@
package cacheops.cache.buffer.read
import java.nio.ByteBuffer
class BufferReader(
val buffer: ByteBuffer
) : Reader {
constructor(array: ByteArray) : this(buffer = ByteBuffer.wrap(array))
override val length: Int = buffer.remaining()
private var bitIndex = 0
override fun readByte(): Int {
return buffer.get().toInt()
}
override fun readByteAdd(): Int {
return (readByte() - 128).toByte().toInt()
}
override fun readByteInverse(): Int {
return -readByte()
}
override fun readByteSubtract(): Int {
return (readByteInverse() + 128).toByte().toInt()
}
override fun readUnsignedByte(): Int {
return readByte() and 0xff
}
override fun readShort(): Int {
return (readByte() shl 8) or readUnsignedByte()
}
override fun readShortAdd(): Int {
return (readByte() shl 8) or readUnsignedByteAdd()
}
override fun readUnsignedShortAdd(): Int {
return (readByte() shl 8) or ((readByte() - 128) and 0xff)
}
override fun readShortLittle(): Int {
return readUnsignedByte() or (readByte() shl 8)
}
override fun readShortAddLittle(): Int {
return readUnsignedByteAdd() or (readByte() shl 8)
}
override fun readUnsignedByteAdd(): Int {
return (readByte() - 128).toByte().toInt()
}
override fun readUnsignedShort(): Int {
return (readUnsignedByte() shl 8) or readUnsignedByte()
}
override fun readUnsignedShortLittle(): Int {
return readUnsignedByte() or (readUnsignedByte() shl 8)
}
override fun readMedium(): Int {
return (readByte() shl 16) or (readByte() shl 8) or readUnsignedByte()
}
override fun readUnsignedMedium(): Int {
return (readUnsignedByte() shl 16) or (readUnsignedByte() shl 8) or readUnsignedByte()
}
override fun readInt(): Int {
return (readUnsignedByte() shl 24) or (readUnsignedByte() shl 16) or (readUnsignedByte() shl 8) or readUnsignedByte()
}
override fun readIntInverseMiddle(): Int {
return (readByte() shl 16) or (readByte() shl 24) or readUnsignedByte() or (readByte() shl 8)
}
override fun readIntLittle(): Int {
return readUnsignedByte() or (readByte() shl 8) or (readByte() shl 16) or (readByte() shl 24)
}
override fun readUnsignedIntMiddle(): Int {
return (readUnsignedByte() shl 8) or readUnsignedByte() or (readUnsignedByte() shl 24) or (readUnsignedByte() shl 16)
}
override fun readSmart(): Int {
val peek = readUnsignedByte()
return if (peek < 128) {
peek and 0xFF
} else {
(peek shl 8 or readUnsignedByte()) - 32768
}
}
override fun readBigSmart(): Int {
val peek = readByte()
return if (peek < 0) {
((peek shl 24) or (readUnsignedByte() shl 16) or (readUnsignedByte() shl 8) or readUnsignedByte()) and 0x7fffffff
} else {
val value = (peek shl 8) or readUnsignedByte()
if (value == 32767) -1 else value
}
}
override fun readLargeSmart(): Int {
var baseValue = 0
var lastValue = readSmart()
while (lastValue == 32767) {
lastValue = readSmart()
baseValue += 32767
}
return baseValue + lastValue
}
override fun readLong(): Long {
val first = readInt().toLong() and 0xffffffffL
val second = readInt().toLong() and 0xffffffffL
return second + (first shl 32)
}
override fun readString(): String {
val sb = StringBuilder()
var b: Int
while (buffer.hasRemaining()) {
b = readByte()
if (b == 0) {
break
}
sb.append(b.toChar())
}
return sb.toString()
}
override fun readBytes(value: ByteArray) {
buffer.get(value)
}
override fun readBytes(array: ByteArray, offset: Int, length: Int) {
buffer.get(array, offset, length)
}
override fun skip(amount: Int) {
buffer.position(buffer.position() + amount)
}
override fun position(): Int {
return buffer.position()
}
override fun position(index: Int) {
buffer.position(index)
}
override fun array(): ByteArray {
return buffer.array()
}
override fun readableBytes(): Int {
return buffer.remaining()
}
override fun startBitAccess(): Reader {
bitIndex = buffer.position() * 8
return this
}
override fun finishBitAccess(): Reader {
buffer.position((bitIndex + 7) / 8)
return this
}
@Suppress("NAME_SHADOWING")
override fun readBits(bitCount: Int): Int {
if (bitCount < 0 || bitCount > 32) {
throw IllegalArgumentException("Number of bits must be between 1 and 32 inclusive")
}
var bitCount = bitCount
var bytePos = bitIndex shr 3
var bitOffset = 8 - (bitIndex and 7)
var value = 0
bitIndex += bitCount
while (bitCount > bitOffset) {
value += buffer.get(bytePos++).toInt() and BIT_MASKS[bitOffset] shl bitCount - bitOffset
bitCount -= bitOffset
bitOffset = 8
}
value += if (bitCount == bitOffset) {
buffer.get(bytePos).toInt() and BIT_MASKS[bitOffset]
} else {
buffer.get(bytePos).toInt() shr bitOffset - bitCount and BIT_MASKS[bitCount]
}
return value
}
fun readIncrSmallSmart(): Int {
var var3: Int = readSmart()
var value = 0
while (32767 == var3) {
var3 = readSmart()
value += 32767
}
value += var3
return value
}
companion object {
/**
* Bit masks for [readBits]
*/
private val BIT_MASKS = IntArray(32)
init {
for (i in BIT_MASKS.indices)
BIT_MASKS[i] = (1 shl i) - 1
}
}
}

View file

@ -0,0 +1,116 @@
package cacheops.cache.buffer.read
interface Reader {
/**
* Starting length of the packet
*/
val length: Int
fun readBoolean() = readByte() == 1
fun readBooleanAdd() = readByteAdd() == 1
fun readBooleanInverse() = readByteInverse() == 1
fun readBooleanSubtract() = readByteSubtract() == 1
fun readUnsignedBoolean() = readUnsignedByte() == 1
fun readByte(): Int
fun readByteAdd(): Int
fun readByteInverse(): Int
fun readByteSubtract(): Int
fun readUnsignedByte(): Int
fun readUnsignedByteAdd(): Int
fun readShort(): Int
fun readShortAdd(): Int
fun readShortLittle(): Int
fun readShortAddLittle(): Int
fun readUnsignedShort(): Int
fun readUnsignedShortLittle(): Int
fun readUnsignedShortAdd(): Int
fun readMedium(): Int
fun readUnsignedMedium(): Int
fun readInt(): Int
fun readIntInverseMiddle(): Int
fun readIntLittle(): Int
fun readUnsignedIntMiddle(): Int
fun readSmart(): Int
fun readBigSmart(): Int
fun readLargeSmart(): Int
fun readLong(): Long
fun readString(): String
/**
* Reads all bytes into [ByteArray]
* @param value The array to be written to.
*/
fun readBytes(value: ByteArray)
/**
* Reads [length] number of bytes starting at [offset] to [array].
* @param array The [ByteArray] to be written to
* @param offset Destination index
* @param length Number of bytes to read
*/
fun readBytes(array: ByteArray, offset: Int, length: Int = array.size)
/**
* Skips the [amount] bytes.
* @param amount Number of bytes to skip
*/
fun skip(amount: Int)
fun position(): Int
fun array(): ByteArray
fun position(index: Int)
/**
* Returns the remaining number of readable bytes.
* @return [Int]
*/
fun readableBytes(): Int
/**
* Enables individual decoded byte writing aka 'bit access'
*/
fun startBitAccess(): Reader
/**
* Disables 'bit access'
*/
fun finishBitAccess(): Reader
/**
* Writes a bit during 'bit access'
* @param bitCount number of bits to be written
* @param value bit value to be set
*/
fun readBits(bitCount: Int): Int
}

View file

@ -0,0 +1,206 @@
package cacheops.cache.buffer.write
import java.nio.ByteBuffer
/**
* All functions relative to writing directly to a packet are done by this class
*/
class BufferWriter(
capacity: Int = 64,
private val buffer: ByteBuffer = ByteBuffer.allocate(capacity)
) : Writer {
private var bitIndex = 0
override fun writeByte(value: Int) {
buffer.put(value.toByte())
}
override fun writeByteAdd(value: Int) {
writeByte(value + 128)
}
override fun writeByteInverse(value: Int) {
writeByte(-value)
}
override fun writeByteSubtract(value: Int) {
writeByte(-value + 128)
}
override fun setByte(index: Int, value: Int) {
buffer.put(index, value.toByte())
}
override fun writeShort(value: Int) {
writeByte(value shr 8)
writeByte(value)
}
override fun writeShortAdd(value: Int) {
writeByte(value shr 8)
writeByteAdd(value)
}
override fun writeShortLittle(value: Int) {
writeByte(value)
writeByte(value shr 8)
}
override fun writeShortAddLittle(value: Int) {
writeByteAdd(value)
writeByte(value shr 8)
}
override fun writeMedium(value: Int) {
writeByte(value shr 16)
writeByte(value shr 8)
writeByte(value)
}
override fun writeInt(value: Int) {
writeByte(value shr 24)
writeByte(value shr 16)
writeByte(value shr 8)
writeByte(value)
}
override fun writeIntMiddle(value: Int) {
writeByte(value shr 8)
writeByte(value)
writeByte(value shr 24)
writeByte(value shr 16)
}
override fun writeIntInverse(value: Int) {
writeByte(value shr 8)
writeByte(value shr 24)
writeByte(value shr 16)
writeByteInverse(value)
}
override fun writeIntInverseMiddle(value: Int) {
writeByte(value shr 16)
writeByte(value shr 24)
writeByte(value)
writeByte(value shr 8)
}
override fun writeIntLittle(value: Int) {
writeByte(value)
writeByte(value shr 8)
writeByte(value shr 16)
writeByte(value shr 24)
}
override fun writeIntInverseLittle(value: Int) {
writeByteInverse(value)
writeByte(value shr 8)
writeByte(value shr 16)
writeByte(value shr 24)
}
override fun writeLong(value: Long) {
writeByte((value shr 56).toInt())
writeByte((value shr 48).toInt())
writeByte((value shr 40).toInt())
writeByte((value shr 32).toInt())
writeByte((value shr 24).toInt())
writeByte((value shr 16).toInt())
writeByte((value shr 8).toInt())
writeByte(value.toInt())
}
override fun writeBytes(value: ByteArray) {
buffer.put(value)
}
override fun writeBytes(data: ByteArray, offset: Int, length: Int) {
buffer.put(data, offset, length)
}
override fun startBitAccess() {
bitIndex = buffer.position() * 8
}
override fun finishBitAccess() {
buffer.position((bitIndex + 7) / 8)
}
override fun writeBits(bitCount: Int, value: Boolean) {
writeBits(bitCount, if (value) 1 else 0)
}
override fun writeBits(bitCount: Int, value: Int) {
var numBits = bitCount
var byteIndex = bitIndex shr 3
var bitOffset = 8 - (bitIndex and 7)
bitIndex += numBits
var tmp: Int
var max: Int
while (numBits > bitOffset) {
tmp = buffer.get(byteIndex).toInt()
max = BIT_MASKS[bitOffset]
tmp = tmp and max.inv() or (value shr numBits - bitOffset and max)
buffer.put(byteIndex++, tmp.toByte())
numBits -= bitOffset
bitOffset = 8
}
tmp = buffer.get(byteIndex).toInt()
max = BIT_MASKS[numBits]
if (numBits == bitOffset) {
tmp = tmp and max.inv() or (value and max)
} else {
tmp = tmp and (max shl bitOffset - numBits).inv()
tmp = tmp or (value and max shl bitOffset - numBits)
}
buffer.put(byteIndex, tmp.toByte())
}
override fun position(): Int {
return buffer.position()
}
override fun position(index: Int) {
buffer.position(index)
}
override fun toArray(): ByteArray {
val data = ByteArray(position())
System.arraycopy(buffer.array(), 0, data, 0, data.size)
return data
}
override fun array(): ByteArray {
return buffer.array()
}
override fun clear() {
buffer.clear()
}
override fun remaining(): Int {
return buffer.remaining()
}
override fun writeIncrSmallSmart(value: Int) {
if (value < 128) {
writeByte(value)
} else {
writeShort(0x8000 or value)
}
}
companion object {
val BIT_MASKS = IntArray(32)
init {
for (i in BIT_MASKS.indices) {
BIT_MASKS[i] = (1 shl i) - 1
}
}
}
}

View file

@ -0,0 +1,101 @@
package cacheops.cache.buffer.write
/**
* All functions relative to writing directly to a packet are done by this class
*/
interface Writer {
fun setByte(index: Int, value: Int)
fun writeByte(value: Int)
fun writeByteAdd(value: Int)
fun writeByteInverse(value: Int)
fun writeByteSubtract(value: Int)
fun writeByte(value: Boolean) {
writeByte(if (value) 1 else 0)
}
fun writeShort(value: Int)
fun writeShortAdd(value: Int)
fun writeShortLittle(value: Int)
fun writeShortAddLittle(value: Int)
fun writeMedium(value: Int)
fun writeInt(value: Int)
fun writeIntMiddle(value: Int)
fun writeIntInverse(value: Int)
fun writeIntInverseMiddle(value: Int)
fun writeIntLittle(value: Int)
fun writeIntInverseLittle(value: Int)
fun writeLong(value: Long)
fun writeSmart(value: Int) {
if (value >= 128) {
writeShort(value + 32768)
} else {
writeByte(value)
}
}
fun writeString(value: String?) {
if (value != null) {
writeBytes(value.toByteArray())
}
writeByte(0)
}
fun writePrefixedString(value: String) {
writeByte(0)
writeBytes(value.toByteArray())
writeByte(0)
}
fun writeBytes(value: ByteArray)
fun writeBytes(data: ByteArray, offset: Int, length: Int)
fun startBitAccess()
fun finishBitAccess()
fun writeBits(bitCount: Int, value: Boolean) {
writeBits(bitCount, if (value) 1 else 0)
}
fun writeBits(bitCount: Int, value: Int)
fun skip(position: Int) {
for (i in 0 until position) {
writeByte(0)
}
}
fun position(): Int
fun position(index: Int)
fun toArray(): ByteArray
fun array(): ByteArray
fun clear()
fun remaining(): Int
fun writeIncrSmallSmart(value: Int)
}

View file

@ -0,0 +1,15 @@
package cacheops.cache.definition
import cacheops.cache.buffer.read.Reader
interface ColorPalette {
var recolourPalette: ByteArray?
fun readColourPalette(buffer: Reader) {
val length = buffer.readUnsignedByte()
recolourPalette = ByteArray(length)
repeat(length) { count ->
recolourPalette!![count] = buffer.readByte().toByte()
}
}
}

View file

@ -0,0 +1,16 @@
package cacheops.cache.definition
@Suppress("UNCHECKED_CAST")
interface Extra {
var extras: Map<String, Any>
operator fun <T: Any> get(key: String): T = extras.getValue(key) as T
fun has(key: String) = extras.containsKey(key)
fun getOrNull(key: String): Any? = extras[key]
operator fun <T : Any> get(key: String, defaultValue: T) = getOrNull(key) as? T ?: defaultValue
}

View file

@ -0,0 +1,28 @@
package cacheops.cache.definition
import cacheops.cache.buffer.read.Reader
@Suppress("UNCHECKED_CAST")
interface Parameterized {
var params: HashMap<Long, Any>?
fun <T : Any> getParam(key: Long) = params?.get(key) as T
fun <T : Any> getParamOrNull(key: Long) = params?.get(key) as? T
fun <T : Any> getParam(key: Long, default: T) = params?.get(key) as? T ?: default
fun readParameters(buffer: Reader) {
val length = buffer.readUnsignedByte()
if (length == 0) {
return
}
params = HashMap()
repeat(length) {
val string = buffer.readUnsignedBoolean()
val id = buffer.readUnsignedMedium().toLong()
params!![id] = if (string) buffer.readString() else buffer.readInt()
}
}
}

View file

@ -0,0 +1,30 @@
package cacheops.cache.definition
import cacheops.cache.buffer.read.Reader
interface Recolourable {
var originalColours: ShortArray?
var modifiedColours: ShortArray?
var originalTextureColours: ShortArray?
var modifiedTextureColours: ShortArray?
fun readColours(buffer: Reader) {
val length = buffer.readUnsignedByte()
originalColours = ShortArray(length)
modifiedColours = ShortArray(length)
repeat(length) { count ->
originalColours!![count] = buffer.readUnsignedShort().toShort()
modifiedColours!![count] = buffer.readUnsignedShort().toShort()
}
}
fun readTextures(buffer: Reader) {
val length = buffer.readUnsignedByte()
originalTextureColours = ShortArray(length)
modifiedTextureColours = ShortArray(length)
repeat(length) { count ->
originalTextureColours!![count] = buffer.readUnsignedShort().toShort()
modifiedTextureColours!![count] = buffer.readUnsignedShort().toShort()
}
}
}

View file

@ -0,0 +1,124 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import cacheops.cache.definition.Extra
data class AnimationDefinition(
override var id: Int = -1,
var durations: IntArray? = null,
var primaryFrames: IntArray? = null,
var loopOffset: Int = -1,
var interleaveOrder: BooleanArray? = null,
var priority: Int = 5,
var leftHandItem: Int = -1,
var rightHandItem: Int = -1,
var maxLoops: Int = 99,
var animatingPrecedence: Int = -1,
var walkingPrecedence: Int = -1,
var replayMode: Int = 2,
var secondaryFrames: IntArray? = null,
var anIntArrayArray700: Array<IntArray?>? = null,
var aBoolean691: Boolean = false,
var tweened: Boolean = false,
var aBoolean699: Boolean = false,
var anIntArray701: IntArray? = null,
var anIntArray690: IntArray? = null,
var anIntArray692: IntArray? = null,
override var extras: Map<String, Any> = emptyMap()
) : Definition, Extra {
val time: Long
get() = (durations?.sum() ?: 0) * 20L
val clientTicks: Int
get() {
if (durations == null) {
return 0
}
var total = 0
for (i in 0 until durations!!.size - 3) {
total += durations!![i]
}
return total
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as AnimationDefinition
if (id != other.id) return false
if (durations != null) {
if (other.durations == null) return false
if (!durations!!.contentEquals(other.durations!!)) return false
} else if (other.durations != null) return false
if (primaryFrames != null) {
if (other.primaryFrames == null) return false
if (!primaryFrames!!.contentEquals(other.primaryFrames!!)) return false
} else if (other.primaryFrames != null) return false
if (loopOffset != other.loopOffset) return false
if (interleaveOrder != null) {
if (other.interleaveOrder == null) return false
if (!interleaveOrder!!.contentEquals(other.interleaveOrder!!)) return false
} else if (other.interleaveOrder != null) return false
if (priority != other.priority) return false
if (leftHandItem != other.leftHandItem) return false
if (rightHandItem != other.rightHandItem) return false
if (maxLoops != other.maxLoops) return false
if (animatingPrecedence != other.animatingPrecedence) return false
if (walkingPrecedence != other.walkingPrecedence) return false
if (replayMode != other.replayMode) return false
if (secondaryFrames != null) {
if (other.secondaryFrames == null) return false
if (!secondaryFrames!!.contentEquals(other.secondaryFrames!!)) return false
} else if (other.secondaryFrames != null) return false
if (anIntArrayArray700 != null) {
if (other.anIntArrayArray700 == null) return false
if (!anIntArrayArray700!!.contentDeepEquals(other.anIntArrayArray700!!)) return false
} else if (other.anIntArrayArray700 != null) return false
if (aBoolean691 != other.aBoolean691) return false
if (tweened != other.tweened) return false
if (aBoolean699 != other.aBoolean699) return false
if (anIntArray701 != null) {
if (other.anIntArray701 == null) return false
if (!anIntArray701!!.contentEquals(other.anIntArray701!!)) return false
} else if (other.anIntArray701 != null) return false
if (anIntArray690 != null) {
if (other.anIntArray690 == null) return false
if (!anIntArray690!!.contentEquals(other.anIntArray690!!)) return false
} else if (other.anIntArray690 != null) return false
if (anIntArray692 != null) {
if (other.anIntArray692 == null) return false
if (!anIntArray692!!.contentEquals(other.anIntArray692!!)) return false
} else if (other.anIntArray692 != null) return false
if (extras != other.extras) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + (durations?.contentHashCode() ?: 0)
result = 31 * result + (primaryFrames?.contentHashCode() ?: 0)
result = 31 * result + loopOffset
result = 31 * result + (interleaveOrder?.contentHashCode() ?: 0)
result = 31 * result + priority
result = 31 * result + leftHandItem
result = 31 * result + rightHandItem
result = 31 * result + maxLoops
result = 31 * result + animatingPrecedence
result = 31 * result + walkingPrecedence
result = 31 * result + replayMode
result = 31 * result + (secondaryFrames?.contentHashCode() ?: 0)
result = 31 * result + (anIntArrayArray700?.contentDeepHashCode() ?: 0)
result = 31 * result + aBoolean691.hashCode()
result = 31 * result + tweened.hashCode()
result = 31 * result + aBoolean699.hashCode()
result = 31 * result + (anIntArray701?.contentHashCode() ?: 0)
result = 31 * result + (anIntArray690?.contentHashCode() ?: 0)
result = 31 * result + (anIntArray692?.contentHashCode() ?: 0)
result = 31 * result + extras.hashCode()
return result
}
}

View file

@ -0,0 +1,19 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import ext.Vector3f
//TODO: Maybe finish and come back who knows.
data class AtmosphereDefinition(
override var id: Int = -1,
val DEFAULT_SKY_COLOR: Int = 0x17c439a8,
val DEFAULT_SUN_COLOR: Int = 0x36dac459,
val DEFAULT_SUN_X_POSITION: Float = 0.69921875F,
val DEFAULT_SUN_Y_POSITION: Float = 1.2F,
val DEFAULT_SUN_X_ANGLE: Int = -50,
val DEFAULT_SUN_Y_ANGLE: Int = -60,
val DEFAULT_SUN_Z_ANGLE: Int = -50,
val DEFAULT_SUN_ANGLE: Vector3f = Vector3f(DEFAULT_SUN_X_ANGLE.toFloat(), DEFAULT_SUN_Y_ANGLE.toFloat(), DEFAULT_SUN_Z_ANGLE.toFloat()),
val DEFAULT_SUN_SHININESS: Float = 1.1523438F,
) : Definition

View file

@ -0,0 +1,9 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
data class BlendedTextureDefinition(
override var id: Int = -1,
var renderOnMap: Boolean = false,
var blendedColor: Int = -1
) : Definition

View file

@ -0,0 +1,16 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
/**
* Equipment Slots Definition
*/
@Suppress("ArrayInDataClass")
data class BodyDefinition(
override var id: Int = -1,
var disabledSlots: IntArray = IntArray(0),
var anInt4506: Int = -1,
var anInt4504: Int = -1,
var anIntArray4501: IntArray? = null,
var anIntArray4507: IntArray? = null
) : Definition

View file

@ -0,0 +1,71 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
data class ClientScriptDefinition(
override var id: Int = -1,
var intArgumentCount: Int = 0,
var stringVariableCount: Int = 0,
var longVariableCount: Int = 0,
var intVariableCount: Int = 0,
var stringArgumentCount: Int = 0,
var longArgumentCount: Int = 0,
var switchStatementIndices: Array<List<Pair<Int, Int>>>? = null,
var name: String? = null,
var instructions: IntArray = intArrayOf(),
var stringOperands: Array<String?>? = null,
var longOperands: LongArray? = null,
var intOperands: IntArray? = null
) : Definition {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ClientScriptDefinition
if (id != other.id) return false
if (intArgumentCount != other.intArgumentCount) return false
if (stringVariableCount != other.stringVariableCount) return false
if (longVariableCount != other.longVariableCount) return false
if (intVariableCount != other.intVariableCount) return false
if (stringArgumentCount != other.stringArgumentCount) return false
if (longArgumentCount != other.longArgumentCount) return false
if (switchStatementIndices != null) {
if (other.switchStatementIndices == null) return false
if (!switchStatementIndices!!.contentEquals(other.switchStatementIndices!!)) return false
} else if (other.switchStatementIndices != null) return false
if (name != other.name) return false
if (!instructions.contentEquals(other.instructions)) return false
if (stringOperands != null) {
if (other.stringOperands == null) return false
if (!stringOperands!!.contentEquals(other.stringOperands!!)) return false
} else if (other.stringOperands != null) return false
if (longOperands != null) {
if (other.longOperands == null) return false
if (!longOperands!!.contentEquals(other.longOperands!!)) return false
} else if (other.longOperands != null) return false
if (intOperands != null) {
if (other.intOperands == null) return false
if (!intOperands!!.contentEquals(other.intOperands!!)) return false
} else if (other.intOperands != null) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + intArgumentCount
result = 31 * result + stringVariableCount
result = 31 * result + longVariableCount
result = 31 * result + intVariableCount
result = 31 * result + stringArgumentCount
result = 31 * result + longArgumentCount
result = 31 * result + (switchStatementIndices?.contentHashCode() ?: 0)
result = 31 * result + (name?.hashCode() ?: 0)
result = 31 * result + instructions.contentHashCode()
result = 31 * result + (stringOperands?.contentHashCode() ?: 0)
result = 31 * result + (longOperands?.contentHashCode() ?: 0)
result = 31 * result + (intOperands?.contentHashCode() ?: 0)
return result
}
}

View file

@ -0,0 +1,19 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
data class EnumDefinition(
override var id: Int = -1,
var keyType: Char = 0.toChar(),
var valueType: Char = 0.toChar(),
var defaultString: String = "null",
var defaultInt: Int = 0,
var length: Int = 0,
var map: HashMap<Int, Any>? = null
) : Definition {
fun getKey(value: Any) = map?.filterValues { it == value }?.keys?.firstOrNull() ?: -1
fun getInt(id: Int) = map?.get(id) as? Int ?: defaultInt
fun getString(id: Int) = map?.get(id) as? String ?: defaultString
}

View file

@ -0,0 +1,82 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import cacheops.cache.definition.Extra
import cacheops.cache.definition.Recolourable
data class GraphicDefinition(
override var id: Int = -1,
var modelId: Int = 0,
var animationId: Int = -1,
var sizeXY: Int = 128,
var sizeZ: Int = 128,
var rotation: Int = 0,
var ambience: Int = 0,
var contrast: Int = 0,
var aByte2381: Byte = 0,
var anInt2385: Int = -1,
var aBoolean2402: Boolean = false,
override var originalColours: ShortArray? = null,
override var modifiedColours: ShortArray? = null,
override var originalTextureColours: ShortArray? = null,
override var modifiedTextureColours: ShortArray? = null,
override var extras: Map<String, Any> = emptyMap()
) : Definition, Recolourable, Extra {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as GraphicDefinition
if (id != other.id) return false
if (modelId != other.modelId) return false
if (animationId != other.animationId) return false
if (sizeXY != other.sizeXY) return false
if (sizeZ != other.sizeZ) return false
if (rotation != other.rotation) return false
if (ambience != other.ambience) return false
if (contrast != other.contrast) return false
if (aByte2381 != other.aByte2381) return false
if (anInt2385 != other.anInt2385) return false
if (aBoolean2402 != other.aBoolean2402) return false
if (originalColours != null) {
if (other.originalColours == null) return false
if (!originalColours!!.contentEquals(other.originalColours!!)) return false
} else if (other.originalColours != null) return false
if (modifiedColours != null) {
if (other.modifiedColours == null) return false
if (!modifiedColours!!.contentEquals(other.modifiedColours!!)) return false
} else if (other.modifiedColours != null) return false
if (originalTextureColours != null) {
if (other.originalTextureColours == null) return false
if (!originalTextureColours!!.contentEquals(other.originalTextureColours!!)) return false
} else if (other.originalTextureColours != null) return false
if (modifiedTextureColours != null) {
if (other.modifiedTextureColours == null) return false
if (!modifiedTextureColours!!.contentEquals(other.modifiedTextureColours!!)) return false
} else if (other.modifiedTextureColours != null) return false
if (extras != other.extras) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + modelId
result = 31 * result + animationId
result = 31 * result + sizeXY
result = 31 * result + sizeZ
result = 31 * result + rotation
result = 31 * result + ambience
result = 31 * result + contrast
result = 31 * result + aByte2381
result = 31 * result + anInt2385
result = 31 * result + aBoolean2402.hashCode()
result = 31 * result + (originalColours?.contentHashCode() ?: 0)
result = 31 * result + (modifiedColours?.contentHashCode() ?: 0)
result = 31 * result + (originalTextureColours?.contentHashCode() ?: 0)
result = 31 * result + (modifiedTextureColours?.contentHashCode() ?: 0)
result = 31 * result + extras.hashCode()
return result
}
}

View file

@ -0,0 +1,36 @@
package cacheops.cache.definition.data
import java.awt.image.BufferedImage
@Suppress("ArrayInDataClass")
data class IndexedSprite(
var offsetX: Int = 0,
var offsetY: Int = 0,
var width: Int = 0,
var height: Int = 0,
var deltaHeight: Int = 0,
var deltaWidth: Int = 0,
var alpha: ByteArray? = null
) {
lateinit var raster: ByteArray
lateinit var palette: IntArray
fun toBufferedImage(): BufferedImage {
val bi = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
for (x in 0 until width) {
for (y in 0 until height) {
val i = x + y * width
if (alpha == null) {
val colour = palette[raster[i].toInt() and 255]
if (colour != 0) {
bi.setRGB(x, y, -16777216 or colour)
}
} else {
bi.setRGB(x, y, palette[raster[i].toInt() and 255] or (alpha!![i].toInt() shl 24))
}
}
}
return bi
}
}

View file

@ -0,0 +1,10 @@
package cacheops.cache.definition.data
object Instructions {
const val PUSH_INT = 0
const val PUSH_STRING = 3
const val MERGE_STRINGS = 37
const val CALL_CS2 = 40
const val SWITCH = 51
const val GOTO = 6
}

View file

@ -0,0 +1,409 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import cacheops.cache.definition.Extra
data class InterfaceComponentDefinition(
override var id: Int = -1,
var type: Int = 0,
var unknown: String? = null,
var contentType: Int = 0,
var basePositionX: Int = 0,
var basePositionY: Int = 0,
var baseWidth: Int = 0,
var baseHeight: Int = 0,
var horizontalSizeMode: Byte = 0,
var verticalSizeMode: Byte = 0,
var horizontalPositionMode: Byte = 0,
var verticalPositionMode: Byte = 0,
var parent: Int = -1,
var hidden: Boolean = false,
var disableHover: Boolean = false,
var scrollWidth: Int = 0,
var scrollHeight: Int = 0,
var colour: Int = 0,
var filled: Boolean = false,
var alpha: Int = 0,
var fontId: Int = -1,
var monochrome: Boolean = true,
var text: String = "",
var lineHeight: Int = 0,
var horizontalTextAlign: Int = 0,
var verticalTextAlign: Int = 0,
var shaded: Boolean = false,
var lineCount: Int = 0,
var defaultImage: Int = -1,
var imageRotation: Int = 0,
var aBoolean4861: Boolean = false,
var imageRepeat: Boolean = false,
var rotation: Int = 0,
var backgroundColour: Int = 0,
var flipVertical: Boolean = false,
var flipHorizontal: Boolean = false,
var aBoolean4782: Boolean = true,
var defaultMediaType: Int = 1,
var defaultMediaId: Int = 0,
var animated: Boolean = false,
var centreType: Boolean = false,
var ignoreZBuffer: Boolean = false,
var viewportX: Int = 0,
var viewportY: Int = 0,
var viewportZ: Int = 0,
var spritePitch: Int = 0,
var spriteRoll: Int = 0,
var spriteYaw: Int = 0,
var spriteScale: Int = 100,
var animation: Int = -1,
var viewportWidth: Int = 0,
var viewportHeight: Int = 0,
var lineWidth: Int = 1,
var lineMirrored: Boolean = false,
var keyRepeat: ByteArray? = null,
var keyCodes: ByteArray? = null,
var keyModifiers: IntArray? = null,
var clickable: Boolean = false,
var name: String = "",
var options: Array<String>? = null,
var mouseIcon: IntArray? = null,
var optionOverride: String? = null,
var anInt4708: Int = 0,// Drag type
var anInt4795: Int = 0,// Drag slider?
var anInt4860: Int = 0,// Friends list icons/buttons?
var useOption: String = "",
var anInt4698: Int = -1,
var anInt4839: Int = -1,// Unused
var anInt4761: Int = -1,// Unused
var setting: InterfaceComponentSetting = InterfaceComponentSetting(0, -1),
val params: HashMap<Long, Any>? = null,
var anObjectArray4758: Array<Any>? = null,
var mouseEnterHandler: Array<Any>? = null,
var mouseExitHandler: Array<Any>? = null,
var anObjectArray4771: Array<Any>? = null,
var anObjectArray4768: Array<Any>? = null,
var stateChangeHandler: Array<Any>? = null,
var invUpdateHandler: Array<Any>? = null,
var refreshHandler: Array<Any>? = null,
var updateHandler: Array<Any>? = null,
var anObjectArray4770: Array<Any>? = null,
var anObjectArray4751: Array<Any>? = null,
var mouseMotionHandler: Array<Any>? = null,
var mousePressedHandler: Array<Any>? = null,
var mouseDraggedHandler: Array<Any>? = null,
var mouseReleasedHandler: Array<Any>? = null,
var mouseDragPassHandler: Array<Any>? = null,
var anObjectArray4852: Array<Any>? = null,
var anObjectArray4711: Array<Any>? = null,
var anObjectArray4753: Array<Any>? = null,
var anObjectArray4688: Array<Any>? = null,
var anObjectArray4775: Array<Any>? = null,
var clientVarp: IntArray? = null,
var containers: IntArray? = null,
var anIntArray4789: IntArray? = null,
var clientVarc: IntArray? = null,
var anIntArray4805: IntArray? = null,
var hasScript: Boolean = false,
override var extras: Map<String, Any> = emptyMap()
) : Definition, Extra {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as InterfaceComponentDefinition
if (id != other.id) return false
if (type != other.type) return false
if (unknown != other.unknown) return false
if (contentType != other.contentType) return false
if (basePositionX != other.basePositionX) return false
if (basePositionY != other.basePositionY) return false
if (baseWidth != other.baseWidth) return false
if (baseHeight != other.baseHeight) return false
if (horizontalSizeMode != other.horizontalSizeMode) return false
if (verticalSizeMode != other.verticalSizeMode) return false
if (horizontalPositionMode != other.horizontalPositionMode) return false
if (verticalPositionMode != other.verticalPositionMode) return false
if (parent != other.parent) return false
if (hidden != other.hidden) return false
if (disableHover != other.disableHover) return false
if (scrollWidth != other.scrollWidth) return false
if (scrollHeight != other.scrollHeight) return false
if (colour != other.colour) return false
if (filled != other.filled) return false
if (alpha != other.alpha) return false
if (fontId != other.fontId) return false
if (monochrome != other.monochrome) return false
if (text != other.text) return false
if (lineHeight != other.lineHeight) return false
if (horizontalTextAlign != other.horizontalTextAlign) return false
if (verticalTextAlign != other.verticalTextAlign) return false
if (shaded != other.shaded) return false
if (lineCount != other.lineCount) return false
if (defaultImage != other.defaultImage) return false
if (imageRotation != other.imageRotation) return false
if (aBoolean4861 != other.aBoolean4861) return false
if (imageRepeat != other.imageRepeat) return false
if (rotation != other.rotation) return false
if (backgroundColour != other.backgroundColour) return false
if (flipVertical != other.flipVertical) return false
if (flipHorizontal != other.flipHorizontal) return false
if (aBoolean4782 != other.aBoolean4782) return false
if (defaultMediaType != other.defaultMediaType) return false
if (defaultMediaId != other.defaultMediaId) return false
if (animated != other.animated) return false
if (centreType != other.centreType) return false
if (ignoreZBuffer != other.ignoreZBuffer) return false
if (viewportX != other.viewportX) return false
if (viewportY != other.viewportY) return false
if (viewportZ != other.viewportZ) return false
if (spritePitch != other.spritePitch) return false
if (spriteRoll != other.spriteRoll) return false
if (spriteYaw != other.spriteYaw) return false
if (spriteScale != other.spriteScale) return false
if (animation != other.animation) return false
if (viewportWidth != other.viewportWidth) return false
if (viewportHeight != other.viewportHeight) return false
if (lineWidth != other.lineWidth) return false
if (lineMirrored != other.lineMirrored) return false
if (keyRepeat != null) {
if (other.keyRepeat == null) return false
if (!keyRepeat!!.contentEquals(other.keyRepeat!!)) return false
} else if (other.keyRepeat != null) return false
if (keyCodes != null) {
if (other.keyCodes == null) return false
if (!keyCodes!!.contentEquals(other.keyCodes!!)) return false
} else if (other.keyCodes != null) return false
if (keyModifiers != null) {
if (other.keyModifiers == null) return false
if (!keyModifiers!!.contentEquals(other.keyModifiers!!)) return false
} else if (other.keyModifiers != null) return false
if (clickable != other.clickable) return false
if (name != other.name) return false
if (options != null) {
if (other.options == null) return false
if (!options!!.contentEquals(other.options!!)) return false
} else if (other.options != null) return false
if (mouseIcon != null) {
if (other.mouseIcon == null) return false
if (!mouseIcon!!.contentEquals(other.mouseIcon!!)) return false
} else if (other.mouseIcon != null) return false
if (optionOverride != other.optionOverride) return false
if (anInt4708 != other.anInt4708) return false
if (anInt4795 != other.anInt4795) return false
if (anInt4860 != other.anInt4860) return false
if (useOption != other.useOption) return false
if (anInt4698 != other.anInt4698) return false
if (anInt4839 != other.anInt4839) return false
if (anInt4761 != other.anInt4761) return false
if (setting != other.setting) return false
if (params != other.params) return false
if (anObjectArray4758 != null) {
if (other.anObjectArray4758 == null) return false
if (!anObjectArray4758!!.contentEquals(other.anObjectArray4758!!)) return false
} else if (other.anObjectArray4758 != null) return false
if (mouseEnterHandler != null) {
if (other.mouseEnterHandler == null) return false
if (!mouseEnterHandler!!.contentEquals(other.mouseEnterHandler!!)) return false
} else if (other.mouseEnterHandler != null) return false
if (mouseExitHandler != null) {
if (other.mouseExitHandler == null) return false
if (!mouseExitHandler!!.contentEquals(other.mouseExitHandler!!)) return false
} else if (other.mouseExitHandler != null) return false
if (anObjectArray4771 != null) {
if (other.anObjectArray4771 == null) return false
if (!anObjectArray4771!!.contentEquals(other.anObjectArray4771!!)) return false
} else if (other.anObjectArray4771 != null) return false
if (anObjectArray4768 != null) {
if (other.anObjectArray4768 == null) return false
if (!anObjectArray4768!!.contentEquals(other.anObjectArray4768!!)) return false
} else if (other.anObjectArray4768 != null) return false
if (stateChangeHandler != null) {
if (other.stateChangeHandler == null) return false
if (!stateChangeHandler!!.contentEquals(other.stateChangeHandler!!)) return false
} else if (other.stateChangeHandler != null) return false
if (invUpdateHandler != null) {
if (other.invUpdateHandler == null) return false
if (!invUpdateHandler!!.contentEquals(other.invUpdateHandler!!)) return false
} else if (other.invUpdateHandler != null) return false
if (refreshHandler != null) {
if (other.refreshHandler == null) return false
if (!refreshHandler!!.contentEquals(other.refreshHandler!!)) return false
} else if (other.refreshHandler != null) return false
if (updateHandler != null) {
if (other.updateHandler == null) return false
if (!updateHandler!!.contentEquals(other.updateHandler!!)) return false
} else if (other.updateHandler != null) return false
if (anObjectArray4770 != null) {
if (other.anObjectArray4770 == null) return false
if (!anObjectArray4770!!.contentEquals(other.anObjectArray4770!!)) return false
} else if (other.anObjectArray4770 != null) return false
if (anObjectArray4751 != null) {
if (other.anObjectArray4751 == null) return false
if (!anObjectArray4751!!.contentEquals(other.anObjectArray4751!!)) return false
} else if (other.anObjectArray4751 != null) return false
if (mouseMotionHandler != null) {
if (other.mouseMotionHandler == null) return false
if (!mouseMotionHandler!!.contentEquals(other.mouseMotionHandler!!)) return false
} else if (other.mouseMotionHandler != null) return false
if (mousePressedHandler != null) {
if (other.mousePressedHandler == null) return false
if (!mousePressedHandler!!.contentEquals(other.mousePressedHandler!!)) return false
} else if (other.mousePressedHandler != null) return false
if (mouseDraggedHandler != null) {
if (other.mouseDraggedHandler == null) return false
if (!mouseDraggedHandler!!.contentEquals(other.mouseDraggedHandler!!)) return false
} else if (other.mouseDraggedHandler != null) return false
if (mouseReleasedHandler != null) {
if (other.mouseReleasedHandler == null) return false
if (!mouseReleasedHandler!!.contentEquals(other.mouseReleasedHandler!!)) return false
} else if (other.mouseReleasedHandler != null) return false
if (mouseDragPassHandler != null) {
if (other.mouseDragPassHandler == null) return false
if (!mouseDragPassHandler!!.contentEquals(other.mouseDragPassHandler!!)) return false
} else if (other.mouseDragPassHandler != null) return false
if (anObjectArray4852 != null) {
if (other.anObjectArray4852 == null) return false
if (!anObjectArray4852!!.contentEquals(other.anObjectArray4852!!)) return false
} else if (other.anObjectArray4852 != null) return false
if (anObjectArray4711 != null) {
if (other.anObjectArray4711 == null) return false
if (!anObjectArray4711!!.contentEquals(other.anObjectArray4711!!)) return false
} else if (other.anObjectArray4711 != null) return false
if (anObjectArray4753 != null) {
if (other.anObjectArray4753 == null) return false
if (!anObjectArray4753!!.contentEquals(other.anObjectArray4753!!)) return false
} else if (other.anObjectArray4753 != null) return false
if (anObjectArray4688 != null) {
if (other.anObjectArray4688 == null) return false
if (!anObjectArray4688!!.contentEquals(other.anObjectArray4688!!)) return false
} else if (other.anObjectArray4688 != null) return false
if (anObjectArray4775 != null) {
if (other.anObjectArray4775 == null) return false
if (!anObjectArray4775!!.contentEquals(other.anObjectArray4775!!)) return false
} else if (other.anObjectArray4775 != null) return false
if (clientVarp != null) {
if (other.clientVarp == null) return false
if (!clientVarp!!.contentEquals(other.clientVarp!!)) return false
} else if (other.clientVarp != null) return false
if (containers != null) {
if (other.containers == null) return false
if (!containers!!.contentEquals(other.containers!!)) return false
} else if (other.containers != null) return false
if (anIntArray4789 != null) {
if (other.anIntArray4789 == null) return false
if (!anIntArray4789!!.contentEquals(other.anIntArray4789!!)) return false
} else if (other.anIntArray4789 != null) return false
if (clientVarc != null) {
if (other.clientVarc == null) return false
if (!clientVarc!!.contentEquals(other.clientVarc!!)) return false
} else if (other.clientVarc != null) return false
if (anIntArray4805 != null) {
if (other.anIntArray4805 == null) return false
if (!anIntArray4805!!.contentEquals(other.anIntArray4805!!)) return false
} else if (other.anIntArray4805 != null) return false
if (hasScript != other.hasScript) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + type
result = 31 * result + (unknown?.hashCode() ?: 0)
result = 31 * result + contentType
result = 31 * result + basePositionX
result = 31 * result + basePositionY
result = 31 * result + baseWidth
result = 31 * result + baseHeight
result = 31 * result + horizontalSizeMode
result = 31 * result + verticalSizeMode
result = 31 * result + horizontalPositionMode
result = 31 * result + verticalPositionMode
result = 31 * result + parent
result = 31 * result + hidden.hashCode()
result = 31 * result + disableHover.hashCode()
result = 31 * result + scrollWidth
result = 31 * result + scrollHeight
result = 31 * result + colour
result = 31 * result + filled.hashCode()
result = 31 * result + alpha
result = 31 * result + fontId
result = 31 * result + monochrome.hashCode()
result = 31 * result + text.hashCode()
result = 31 * result + lineHeight
result = 31 * result + horizontalTextAlign
result = 31 * result + verticalTextAlign
result = 31 * result + shaded.hashCode()
result = 31 * result + lineCount
result = 31 * result + defaultImage
result = 31 * result + imageRotation
result = 31 * result + aBoolean4861.hashCode()
result = 31 * result + imageRepeat.hashCode()
result = 31 * result + rotation
result = 31 * result + backgroundColour
result = 31 * result + flipVertical.hashCode()
result = 31 * result + flipHorizontal.hashCode()
result = 31 * result + aBoolean4782.hashCode()
result = 31 * result + defaultMediaType
result = 31 * result + defaultMediaId
result = 31 * result + animated.hashCode()
result = 31 * result + centreType.hashCode()
result = 31 * result + ignoreZBuffer.hashCode()
result = 31 * result + viewportX
result = 31 * result + viewportY
result = 31 * result + viewportZ
result = 31 * result + spritePitch
result = 31 * result + spriteRoll
result = 31 * result + spriteYaw
result = 31 * result + spriteScale
result = 31 * result + animation
result = 31 * result + viewportWidth
result = 31 * result + viewportHeight
result = 31 * result + lineWidth
result = 31 * result + lineMirrored.hashCode()
result = 31 * result + (keyRepeat?.contentHashCode() ?: 0)
result = 31 * result + (keyCodes?.contentHashCode() ?: 0)
result = 31 * result + (keyModifiers?.contentHashCode() ?: 0)
result = 31 * result + clickable.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + (options?.contentHashCode() ?: 0)
result = 31 * result + (mouseIcon?.contentHashCode() ?: 0)
result = 31 * result + (optionOverride?.hashCode() ?: 0)
result = 31 * result + anInt4708
result = 31 * result + anInt4795
result = 31 * result + anInt4860
result = 31 * result + useOption.hashCode()
result = 31 * result + anInt4698
result = 31 * result + anInt4839
result = 31 * result + anInt4761
result = 31 * result + setting.hashCode()
result = 31 * result + (params?.hashCode() ?: 0)
result = 31 * result + (anObjectArray4758?.contentHashCode() ?: 0)
result = 31 * result + (mouseEnterHandler?.contentHashCode() ?: 0)
result = 31 * result + (mouseExitHandler?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4771?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4768?.contentHashCode() ?: 0)
result = 31 * result + (stateChangeHandler?.contentHashCode() ?: 0)
result = 31 * result + (invUpdateHandler?.contentHashCode() ?: 0)
result = 31 * result + (refreshHandler?.contentHashCode() ?: 0)
result = 31 * result + (updateHandler?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4770?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4751?.contentHashCode() ?: 0)
result = 31 * result + (mouseMotionHandler?.contentHashCode() ?: 0)
result = 31 * result + (mousePressedHandler?.contentHashCode() ?: 0)
result = 31 * result + (mouseDraggedHandler?.contentHashCode() ?: 0)
result = 31 * result + (mouseReleasedHandler?.contentHashCode() ?: 0)
result = 31 * result + (mouseDragPassHandler?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4852?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4711?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4753?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4688?.contentHashCode() ?: 0)
result = 31 * result + (anObjectArray4775?.contentHashCode() ?: 0)
result = 31 * result + (clientVarp?.contentHashCode() ?: 0)
result = 31 * result + (containers?.contentHashCode() ?: 0)
result = 31 * result + (anIntArray4789?.contentHashCode() ?: 0)
result = 31 * result + (clientVarc?.contentHashCode() ?: 0)
result = 31 * result + (anIntArray4805?.contentHashCode() ?: 0)
result = 31 * result + hasScript.hashCode()
return result
}
}

View file

@ -0,0 +1,27 @@
package cacheops.cache.definition.data
data class InterfaceComponentSetting(var setting: Int, var anInt7413: Int) {
fun method2743(): Int {
return setting and 0x3fda8 shr 11
}
fun method2744(): Boolean {
return 0x1 and setting shr 22 != 0
}
fun method2745(): Int {
return 0x1d36c1 and setting shr 18
}
fun method2746(): Boolean {
return 0x1 and setting != 0
}
fun method2747(): Boolean {
return 0x1 and setting shr 21 != 0
}
fun unlockedSlot(slot: Int): Boolean {
return 0x1 and setting shr slot + 1 != 0
}
}

View file

@ -0,0 +1,11 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import cacheops.cache.definition.Extra
@Suppress("ArrayInDataClass")
data class InterfaceDefinition(
override var id: Int = -1,
var components: Map<Int, InterfaceComponentDefinition>? = null,
override var extras: Map<String, Any> = emptyMap()
) : Definition, Extra

View file

@ -0,0 +1,249 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import cacheops.cache.definition.ColorPalette
import cacheops.cache.definition.Extra
import cacheops.cache.definition.Parameterized
import cacheops.cache.definition.Recolourable
data class ItemDefinition(
override var id: Int = -1,
var modelId: Int = 0,
var name: String = "null",
var spriteScale: Int = 2000,
var spritePitch: Int = 0,
var spriteCameraRoll: Int = 0,
var spriteTranslateX: Int = 0,
var spriteTranslateY: Int = 0,
var stackable: Int = 0,
var cost: Int = 1,
var members: Boolean = false,
var multiStackSize: Int = -1,
var primaryMaleModel: Int = -1,
var secondaryMaleModel: Int = -1,
var primaryFemaleModel: Int = -1,
var secondaryFemaleModel: Int = -1,
var floorOptions: Array<String?> = arrayOf(null, null, "Take", null, null, "Examine"),
var options: Array<String?> = arrayOf(null, null, null, null, "Drop"),
override var originalColours: ShortArray? = null,
override var modifiedColours: ShortArray? = null,
override var originalTextureColours: ShortArray? = null,
override var modifiedTextureColours: ShortArray? = null,
override var recolourPalette: ByteArray? = null,
var exchangeable: Boolean = false,
var tertiaryMaleModel: Int = -1,
var tertiaryFemaleModel: Int = -1,
var primaryMaleDialogueHead: Int = -1,
var primaryFemaleDialogueHead: Int = -1,
var secondaryMaleDialogueHead: Int = -1,
var secondaryFemaleDialogueHead: Int = -1,
var spriteCameraYaw: Int = 0,
var dummyItem: Int = 0,
var noteId: Int = -1,
var notedTemplateId: Int = -1,
var stackIds: IntArray? = null,
var stackAmounts: IntArray? = null,
var floorScaleX: Int = 128,
var floorScaleZ: Int = 128,
var floorScaleY: Int = 128,
var ambience: Int = 0,
var diffusion: Int = 0,
var team: Int = 0,
var lendId: Int = -1,
var lendTemplateId: Int = -1,
var maleWieldX: Int = 0,
var maleWieldZ: Int = 0,
var maleWieldY: Int = 0,
var femaleWieldX: Int = 0,
var femaleWieldZ: Int = 0,
var femaleWieldY: Int = 0,
var primaryCursorOpcode: Int = -1,
var primaryCursor: Int = -1,
var secondaryCursorOpcode: Int = -1,
var secondaryCursor: Int = -1,
var primaryInterfaceCursorOpcode: Int = -1,
var primaryInterfaceCursor: Int = -1,
var secondaryInterfaceCursorOpcode: Int = -1,
var secondaryInterfaceCursor: Int = -1,
var campaigns: IntArray? = null,
var pickSizeShift: Int = 0,
var singleNoteId: Int = -1,
var singleNoteTemplateId: Int = -1,
override var params: HashMap<Long, Any>? = null,
override var extras: Map<String, Any> = emptyMap()
) : Definition, Recolourable, ColorPalette, Parameterized, Extra {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ItemDefinition
if (id != other.id) return false
if (modelId != other.modelId) return false
if (name != other.name) return false
if (spriteScale != other.spriteScale) return false
if (spritePitch != other.spritePitch) return false
if (spriteCameraRoll != other.spriteCameraRoll) return false
if (spriteTranslateX != other.spriteTranslateX) return false
if (spriteTranslateY != other.spriteTranslateY) return false
if (stackable != other.stackable) return false
if (cost != other.cost) return false
if (members != other.members) return false
if (multiStackSize != other.multiStackSize) return false
if (primaryMaleModel != other.primaryMaleModel) return false
if (secondaryMaleModel != other.secondaryMaleModel) return false
if (primaryFemaleModel != other.primaryFemaleModel) return false
if (secondaryFemaleModel != other.secondaryFemaleModel) return false
if (!floorOptions.contentEquals(other.floorOptions)) return false
if (!options.contentEquals(other.options)) return false
if (originalColours != null) {
if (other.originalColours == null) return false
if (!originalColours!!.contentEquals(other.originalColours!!)) return false
} else if (other.originalColours != null) return false
if (modifiedColours != null) {
if (other.modifiedColours == null) return false
if (!modifiedColours!!.contentEquals(other.modifiedColours!!)) return false
} else if (other.modifiedColours != null) return false
if (originalTextureColours != null) {
if (other.originalTextureColours == null) return false
if (!originalTextureColours!!.contentEquals(other.originalTextureColours!!)) return false
} else if (other.originalTextureColours != null) return false
if (modifiedTextureColours != null) {
if (other.modifiedTextureColours == null) return false
if (!modifiedTextureColours!!.contentEquals(other.modifiedTextureColours!!)) return false
} else if (other.modifiedTextureColours != null) return false
if (recolourPalette != null) {
if (other.recolourPalette == null) return false
if (!recolourPalette!!.contentEquals(other.recolourPalette!!)) return false
} else if (other.recolourPalette != null) return false
if (exchangeable != other.exchangeable) return false
if (tertiaryMaleModel != other.tertiaryMaleModel) return false
if (tertiaryFemaleModel != other.tertiaryFemaleModel) return false
if (primaryMaleDialogueHead != other.primaryMaleDialogueHead) return false
if (primaryFemaleDialogueHead != other.primaryFemaleDialogueHead) return false
if (secondaryMaleDialogueHead != other.secondaryMaleDialogueHead) return false
if (secondaryFemaleDialogueHead != other.secondaryFemaleDialogueHead) return false
if (spriteCameraYaw != other.spriteCameraYaw) return false
if (dummyItem != other.dummyItem) return false
if (noteId != other.noteId) return false
if (notedTemplateId != other.notedTemplateId) return false
if (stackIds != null) {
if (other.stackIds == null) return false
if (!stackIds!!.contentEquals(other.stackIds!!)) return false
} else if (other.stackIds != null) return false
if (stackAmounts != null) {
if (other.stackAmounts == null) return false
if (!stackAmounts!!.contentEquals(other.stackAmounts!!)) return false
} else if (other.stackAmounts != null) return false
if (floorScaleX != other.floorScaleX) return false
if (floorScaleZ != other.floorScaleZ) return false
if (floorScaleY != other.floorScaleY) return false
if (ambience != other.ambience) return false
if (diffusion != other.diffusion) return false
if (team != other.team) return false
if (lendId != other.lendId) return false
if (lendTemplateId != other.lendTemplateId) return false
if (maleWieldX != other.maleWieldX) return false
if (maleWieldZ != other.maleWieldZ) return false
if (maleWieldY != other.maleWieldY) return false
if (femaleWieldX != other.femaleWieldX) return false
if (femaleWieldZ != other.femaleWieldZ) return false
if (femaleWieldY != other.femaleWieldY) return false
if (primaryCursorOpcode != other.primaryCursorOpcode) return false
if (primaryCursor != other.primaryCursor) return false
if (secondaryCursorOpcode != other.secondaryCursorOpcode) return false
if (secondaryCursor != other.secondaryCursor) return false
if (primaryInterfaceCursorOpcode != other.primaryInterfaceCursorOpcode) return false
if (primaryInterfaceCursor != other.primaryInterfaceCursor) return false
if (secondaryInterfaceCursorOpcode != other.secondaryInterfaceCursorOpcode) return false
if (secondaryInterfaceCursor != other.secondaryInterfaceCursor) return false
if (campaigns != null) {
if (other.campaigns == null) return false
if (!campaigns!!.contentEquals(other.campaigns!!)) return false
} else if (other.campaigns != null) return false
if (pickSizeShift != other.pickSizeShift) return false
if (singleNoteId != other.singleNoteId) return false
if (singleNoteTemplateId != other.singleNoteTemplateId) return false
if (params != other.params) return false
if (extras != other.extras) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + modelId
result = 31 * result + name.hashCode()
result = 31 * result + spriteScale
result = 31 * result + spritePitch
result = 31 * result + spriteCameraRoll
result = 31 * result + spriteTranslateX
result = 31 * result + spriteTranslateY
result = 31 * result + stackable
result = 31 * result + cost
result = 31 * result + members.hashCode()
result = 31 * result + multiStackSize
result = 31 * result + primaryMaleModel
result = 31 * result + secondaryMaleModel
result = 31 * result + primaryFemaleModel
result = 31 * result + secondaryFemaleModel
result = 31 * result + floorOptions.contentHashCode()
result = 31 * result + options.contentHashCode()
result = 31 * result + (originalColours?.contentHashCode() ?: 0)
result = 31 * result + (modifiedColours?.contentHashCode() ?: 0)
result = 31 * result + (originalTextureColours?.contentHashCode() ?: 0)
result = 31 * result + (modifiedTextureColours?.contentHashCode() ?: 0)
result = 31 * result + (recolourPalette?.contentHashCode() ?: 0)
result = 31 * result + exchangeable.hashCode()
result = 31 * result + tertiaryMaleModel
result = 31 * result + tertiaryFemaleModel
result = 31 * result + primaryMaleDialogueHead
result = 31 * result + primaryFemaleDialogueHead
result = 31 * result + secondaryMaleDialogueHead
result = 31 * result + secondaryFemaleDialogueHead
result = 31 * result + spriteCameraYaw
result = 31 * result + dummyItem
result = 31 * result + noteId
result = 31 * result + notedTemplateId
result = 31 * result + (stackIds?.contentHashCode() ?: 0)
result = 31 * result + (stackAmounts?.contentHashCode() ?: 0)
result = 31 * result + floorScaleX
result = 31 * result + floorScaleZ
result = 31 * result + floorScaleY
result = 31 * result + ambience
result = 31 * result + diffusion
result = 31 * result + team
result = 31 * result + lendId
result = 31 * result + lendTemplateId
result = 31 * result + maleWieldX
result = 31 * result + maleWieldZ
result = 31 * result + maleWieldY
result = 31 * result + femaleWieldX
result = 31 * result + femaleWieldZ
result = 31 * result + femaleWieldY
result = 31 * result + primaryCursorOpcode
result = 31 * result + primaryCursor
result = 31 * result + secondaryCursorOpcode
result = 31 * result + secondaryCursor
result = 31 * result + primaryInterfaceCursorOpcode
result = 31 * result + primaryInterfaceCursor
result = 31 * result + secondaryInterfaceCursorOpcode
result = 31 * result + secondaryInterfaceCursor
result = 31 * result + (campaigns?.contentHashCode() ?: 0)
result = 31 * result + pickSizeShift
result = 31 * result + singleNoteId
result = 31 * result + singleNoteTemplateId
result = 31 * result + (params?.hashCode() ?: 0)
result = 31 * result + extras.hashCode()
return result
}
val noted: Boolean
get() = notedTemplateId != -1
val lent: Boolean
get() = lendTemplateId != -1
val singleNote: Boolean
get() = singleNoteTemplateId != -1
}

View file

@ -0,0 +1,24 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
data class MapDefinition(
override var id: Int = -1,
val tiles: MutableMap<Int, MapTile> = mutableMapOf(),
val objects: MutableList<MapObject> = mutableListOf()
) : Definition {
fun getTile(localX: Int, localY: Int, plane: Int) = tiles[getHash(localX, localY, plane)] ?: MapTile.EMPTY
fun setTile(localX: Int, localY: Int, plane: Int, tile: MapTile) {
tiles[getHash(localX, localY, plane)] = tile
}
companion object {
fun getHash(localX: Int, localY: Int, plane: Int): Int {
return localY + (localX shl 6) + (plane shl 12)
}
fun getLocalX(tile: Int) = tile shr 6 and 0x3f
fun getLocalY(tile: Int) = tile and 0x3f
fun getPlane(tile: Int) = tile shr 12 and 0x3
}
}

View file

@ -0,0 +1,43 @@
package cacheops.cache.definition.data
inline class MapObject(val hash: Long) {
constructor(id: Int, x: Int, y: Int, plane: Int, type: Int, rotation: Int) : this(getHash(id, x, y, plane, type, rotation))
val id: Int
get() = getId(hash)
val x: Int
get() = getX(hash)
val y: Int
get() = getY(hash)
val plane: Int
get() = getPlane(hash)
val type: Int
get() = getType(hash)
val rotation: Int
get() = getRotation(hash)
companion object {
fun getHash(id: Int, x: Int, y: Int, plane: Int, type: Int, rotation: Int): Long {
return getHash(id.toLong(), x.toLong(), y.toLong(), plane.toLong(), type.toLong(), rotation.toLong())
}
fun getHash(id: Long, x: Long, y: Long, plane: Long, type: Long, rotation: Long): Long {
return rotation + (type shl 2) + (plane shl 7) + (y shl 9) + (x shl 23) + (id shl 37)
}
fun getId(hash: Long): Int = (hash shr 37 and 0x1ffff).toInt()
fun getX(hash: Long): Int = (hash shr 23 and 0x3fff).toInt()
fun getY(hash: Long): Int = (hash shr 9 and 0x3fff).toInt()
fun getPlane(hash: Long): Int = (hash shr 7 and 0x3).toInt()
fun getType(hash: Long): Int = (hash shr 2 and 0x1f).toInt()
fun getRotation(hash: Long): Int = (hash and 0x3).toInt()
}
}

View file

@ -0,0 +1,58 @@
package cacheops.cache.definition.data
inline class MapTile(val hash: Long) {
constructor(
height: Int = 0,
opcode: Int = 0,
overlay: Int = 0,
path: Int = 0,
rotation: Int = 0,
settings: Int = 0,
underlay: Int = 0
) : this(getHash(height, opcode, overlay, path, rotation, settings, underlay))
val height: Int
get() = getHeight(hash)
val attrOpcode: Int
get() = getOpcode(hash)
val overlayId: Int
get() = getOverlay(hash)
val overlayPath: Int
get() = getPath(hash)
val overlayRotation: Int
get() = getRotation(hash)
val settings: Int
get() = getSettings(hash)
val underlayId: Int
get() = getUnderlay(hash)
fun isTile(flag: Int) = settings and flag == flag
companion object {
val EMPTY = MapTile()
fun getHash(height: Int, opcode: Int, overlay: Int, path: Int, rotation: Int, settings: Int, underlay: Int): Long {
return getHash(height.toLong(), opcode.toLong(), overlay.toLong(), path.toLong(), rotation.toLong(), settings.toLong(), underlay.toLong())
}
fun getHash(height: Long, opcode: Long, overlay: Long, path: Long, rotation: Long, settings: Long, underlay: Long): Long {
return height + (opcode shl 8) + (overlay shl 16) + (path shl 24) + (rotation shl 32) + (settings shl 40) + (underlay shl 48)
}
fun getHeight(hash: Long): Int = (hash and 0xff).toInt()
fun getOpcode(hash: Long): Int = (hash shr 8 and 0xff).toInt()
fun getOverlay(hash: Long): Int = (hash shr 16 and 0xff).toInt()
fun getPath(hash: Long): Int = (hash shr 24 and 0xff).toInt()
fun getRotation(hash: Long): Int = (hash shr 32 and 0xff).toInt()
fun getSettings(hash: Long): Int = (hash shr 40 and 0xff).toInt()
fun getUnderlay(hash: Long): Int = (hash shr 48 and 0xff).toInt()
}
}

View file

@ -0,0 +1,250 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import cacheops.cache.definition.Extra
import cacheops.cache.definition.Parameterized
import cacheops.cache.definition.Recolourable
data class NPCDefinition(
override var id: Int = -1,
var modelIds: IntArray? = null,
var name: String = "null",
var size: Int = 1,
var options: Array<String?> = arrayOf(null, null, null, null, null, "Examine"),
override var originalColours: ShortArray? = null,
override var modifiedColours: ShortArray? = null,
override var originalTextureColours: ShortArray? = null,
override var modifiedTextureColours: ShortArray? = null,
var recolourPalette: ByteArray? = null,
var dialogueModels: IntArray? = null,
var drawMinimapDot: Boolean = true,
var combat: Int = -1,
var scaleXY: Int = 128,
var scaleZ: Int = 128,
var priorityRender: Boolean = false,
var lightModifier: Int = 0,
var shadowModifier: Int = 0,
var headIcon: Int = -1,
var rotation: Int = 32,
var varbit: Int = -1,
var varp: Int = -1,
var morphs: IntArray? = null,
var clickable: Boolean = true,
var slowWalk: Boolean = true,
var animateIdle: Boolean = true,
var primaryShadowColour: Short = 0,
var secondaryShadowColour: Short = 0,
var primaryShadowModifier: Byte = -96,
var secondaryShadowModifier: Byte = -16,
var walkMask: Byte = 0,
var translations: Array<IntArray?>? = null,
var hitbarSprite: Int = -1,
var height: Int = -1,
var respawnDirection: Byte = 4,
var renderEmote: Int = -1,
var idleSound: Int = -1,
var crawlSound: Int = -1,
var walkSound: Int = -1,
var runSound: Int = -1,
var soundDistance: Int = 0,
var primaryCursorOp: Int = -1,
var primaryCursor: Int = -1,
var secondaryCursorOp: Int = -1,
var secondaryCursor: Int = -1,
var attackCursor: Int = -1,
var armyIcon: Int = -1,
var spriteId: Int = -1,
var ambientSoundVolume: Int = 255,
var visiblePriority: Boolean = false,
var mapFunction: Int = -1,
var invisiblePriority: Boolean = false,
var hue: Byte = 0,
var saturation: Byte = 0,
var lightness: Byte = 0,
var opacity: Byte = 0,
var mainOptionIndex: Byte = -1,
var campaigns: IntArray? = null,
var aBoolean2883: Boolean = false,
var anInt2803: Int = -1,
var anInt2844: Int = 256,
var anInt2852: Int = 256,
var anInt2831: Int = 0,
var anInt2862: Int = 0,
override var params: HashMap<Long, Any>? = null,
override var extras: Map<String, Any> = emptyMap()
) : Definition, Recolourable, Parameterized, Extra {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as NPCDefinition
if (id != other.id) return false
if (modelIds != null) {
if (other.modelIds == null) return false
if (!modelIds!!.contentEquals(other.modelIds!!)) return false
} else if (other.modelIds != null) return false
if (name != other.name) return false
if (size != other.size) return false
if (!options.contentEquals(other.options)) return false
if (originalColours != null) {
if (other.originalColours == null) return false
if (!originalColours!!.contentEquals(other.originalColours!!)) return false
} else if (other.originalColours != null) return false
if (modifiedColours != null) {
if (other.modifiedColours == null) return false
if (!modifiedColours!!.contentEquals(other.modifiedColours!!)) return false
} else if (other.modifiedColours != null) return false
if (originalTextureColours != null) {
if (other.originalTextureColours == null) return false
if (!originalTextureColours!!.contentEquals(other.originalTextureColours!!)) return false
} else if (other.originalTextureColours != null) return false
if (modifiedTextureColours != null) {
if (other.modifiedTextureColours == null) return false
if (!modifiedTextureColours!!.contentEquals(other.modifiedTextureColours!!)) return false
} else if (other.modifiedTextureColours != null) return false
if (recolourPalette != null) {
if (other.recolourPalette == null) return false
if (!recolourPalette!!.contentEquals(other.recolourPalette!!)) return false
} else if (other.recolourPalette != null) return false
if (dialogueModels != null) {
if (other.dialogueModels == null) return false
if (!dialogueModels!!.contentEquals(other.dialogueModels!!)) return false
} else if (other.dialogueModels != null) return false
if (drawMinimapDot != other.drawMinimapDot) return false
if (combat != other.combat) return false
if (scaleXY != other.scaleXY) return false
if (scaleZ != other.scaleZ) return false
if (priorityRender != other.priorityRender) return false
if (lightModifier != other.lightModifier) return false
if (shadowModifier != other.shadowModifier) return false
if (headIcon != other.headIcon) return false
if (rotation != other.rotation) return false
if (varbit != other.varbit) return false
if (varp != other.varp) return false
if (morphs != null) {
if (other.morphs == null) return false
if (!morphs!!.contentEquals(other.morphs!!)) return false
} else if (other.morphs != null) return false
if (clickable != other.clickable) return false
if (slowWalk != other.slowWalk) return false
if (animateIdle != other.animateIdle) return false
if (primaryShadowColour != other.primaryShadowColour) return false
if (secondaryShadowColour != other.secondaryShadowColour) return false
if (primaryShadowModifier != other.primaryShadowModifier) return false
if (secondaryShadowModifier != other.secondaryShadowModifier) return false
if (walkMask != other.walkMask) return false
if (translations != null) {
if (other.translations == null) return false
if (!translations!!.contentDeepEquals(other.translations!!)) return false
} else if (other.translations != null) return false
if (hitbarSprite != other.hitbarSprite) return false
if (height != other.height) return false
if (respawnDirection != other.respawnDirection) return false
if (renderEmote != other.renderEmote) return false
if (idleSound != other.idleSound) return false
if (crawlSound != other.crawlSound) return false
if (walkSound != other.walkSound) return false
if (runSound != other.runSound) return false
if (soundDistance != other.soundDistance) return false
if (primaryCursorOp != other.primaryCursorOp) return false
if (primaryCursor != other.primaryCursor) return false
if (secondaryCursorOp != other.secondaryCursorOp) return false
if (secondaryCursor != other.secondaryCursor) return false
if (attackCursor != other.attackCursor) return false
if (armyIcon != other.armyIcon) return false
if (spriteId != other.spriteId) return false
if (ambientSoundVolume != other.ambientSoundVolume) return false
if (visiblePriority != other.visiblePriority) return false
if (mapFunction != other.mapFunction) return false
if (invisiblePriority != other.invisiblePriority) return false
if (hue != other.hue) return false
if (saturation != other.saturation) return false
if (lightness != other.lightness) return false
if (opacity != other.opacity) return false
if (mainOptionIndex != other.mainOptionIndex) return false
if (campaigns != null) {
if (other.campaigns == null) return false
if (!campaigns!!.contentEquals(other.campaigns!!)) return false
} else if (other.campaigns != null) return false
if (aBoolean2883 != other.aBoolean2883) return false
if (anInt2803 != other.anInt2803) return false
if (anInt2844 != other.anInt2844) return false
if (anInt2852 != other.anInt2852) return false
if (anInt2831 != other.anInt2831) return false
if (anInt2862 != other.anInt2862) return false
if (params != other.params) return false
if (extras != other.extras) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + (modelIds?.contentHashCode() ?: 0)
result = 31 * result + name.hashCode()
result = 31 * result + size
result = 31 * result + options.contentHashCode()
result = 31 * result + (originalColours?.contentHashCode() ?: 0)
result = 31 * result + (modifiedColours?.contentHashCode() ?: 0)
result = 31 * result + (originalTextureColours?.contentHashCode() ?: 0)
result = 31 * result + (modifiedTextureColours?.contentHashCode() ?: 0)
result = 31 * result + (recolourPalette?.contentHashCode() ?: 0)
result = 31 * result + (dialogueModels?.contentHashCode() ?: 0)
result = 31 * result + drawMinimapDot.hashCode()
result = 31 * result + combat
result = 31 * result + scaleXY
result = 31 * result + scaleZ
result = 31 * result + priorityRender.hashCode()
result = 31 * result + lightModifier
result = 31 * result + shadowModifier
result = 31 * result + headIcon
result = 31 * result + rotation
result = 31 * result + varbit
result = 31 * result + varp
result = 31 * result + (morphs?.contentHashCode() ?: 0)
result = 31 * result + clickable.hashCode()
result = 31 * result + slowWalk.hashCode()
result = 31 * result + animateIdle.hashCode()
result = 31 * result + primaryShadowColour
result = 31 * result + secondaryShadowColour
result = 31 * result + primaryShadowModifier
result = 31 * result + secondaryShadowModifier
result = 31 * result + walkMask
result = 31 * result + (translations?.contentDeepHashCode() ?: 0)
result = 31 * result + hitbarSprite
result = 31 * result + height
result = 31 * result + respawnDirection
result = 31 * result + renderEmote
result = 31 * result + idleSound
result = 31 * result + crawlSound
result = 31 * result + walkSound
result = 31 * result + runSound
result = 31 * result + soundDistance
result = 31 * result + primaryCursorOp
result = 31 * result + primaryCursor
result = 31 * result + secondaryCursorOp
result = 31 * result + secondaryCursor
result = 31 * result + attackCursor
result = 31 * result + armyIcon
result = 31 * result + spriteId
result = 31 * result + ambientSoundVolume
result = 31 * result + visiblePriority.hashCode()
result = 31 * result + mapFunction
result = 31 * result + invisiblePriority.hashCode()
result = 31 * result + hue
result = 31 * result + saturation
result = 31 * result + lightness
result = 31 * result + opacity
result = 31 * result + mainOptionIndex
result = 31 * result + (campaigns?.contentHashCode() ?: 0)
result = 31 * result + aBoolean2883.hashCode()
result = 31 * result + anInt2803
result = 31 * result + anInt2844
result = 31 * result + anInt2852
result = 31 * result + anInt2831
result = 31 * result + anInt2862
result = 31 * result + (params?.hashCode() ?: 0)
result = 31 * result + extras.hashCode()
return result
}
}

View file

@ -0,0 +1,295 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import cacheops.cache.definition.ColorPalette
import cacheops.cache.definition.Extra
import cacheops.cache.definition.Parameterized
import cacheops.cache.definition.Recolourable
data class ObjectDefinition(
override var id: Int = -1,
var modelIds: IntArray? = null,
var modelTypes: IntArray? = null,
var name: String = "null",
var sizeX: Int = 1,
var sizeY: Int = 1,
var blocksSky: Boolean = true,
var solid: Int = 2,
var interactive: Int = -1,
var contouredGround: Byte = 0,
var delayShading: Boolean = false,
var offsetMultiplier: Int = 64,
var brightness: Int = 0,
var options: Array<String?> = arrayOf(null, null, null, null, null, "Examine"),
var contrast: Int = 0,
override var originalColours: ShortArray? = null,
override var modifiedColours: ShortArray? = null,
override var originalTextureColours: ShortArray? = null,
override var modifiedTextureColours: ShortArray? = null,
override var recolourPalette: ByteArray? = null,
var mirrored: Boolean = false,
var castsShadow: Boolean = true,
var modelSizeX: Int = 128,
var modelSizeZ: Int = 128,
var modelSizeY: Int = 128,
var blockFlag: Int = 0,
var offsetX: Int = 0,
var offsetZ: Int = 0,
var offsetY: Int = 0,
var blocksLand: Boolean = false,
var ignoreOnRoute: Boolean = false,
var supportItems: Int = -1,
var varbitIndex: Int = -1,
var configId: Int = -1,
var configObjectIds: IntArray? = null,
var anInt3015: Int = -1,
var anInt3012: Int = 0,
var anInt2989: Int = 0,
var anInt2971: Int = 0,
var anIntArray3036: IntArray? = null,
var anInt3023: Int = -1,
var hideMinimap: Boolean = false,
var aBoolean2972: Boolean = true,
var animateImmediately: Boolean = true,
var aBoolean1502: Boolean = false,
var aBoolean1507: Boolean = false,
var isMembers: Boolean = false,
var adjustMapSceneRotation: Boolean = false,
var hasAnimation: Boolean = false,
var anInt2987: Int = -1,
var anInt3008: Int = -1,
var anInt3038: Int = -1,
var anInt3013: Int = -1,
var mapSceneRotation: Int = 0,
var mapscene: Int = -1,
var culling: Int = -1,
var anInt3024: Int = 255,
var invertMapScene: Boolean = false,
var animations: IntArray? = null,
var percents: IntArray? = null,
var mapDefinitionId: Int = -1,
var anIntArray2981: IntArray? = null,
var aByte2974: Byte = 0,
var aByte3045: Byte = 0,
var aByte3052: Byte = 0,
var aByte2960: Byte = 0,
var anInt2964: Int = 0,
var anInt2963: Int = 0,
var anInt3018: Int = 0,
var anInt2983: Int = 0,
var aBoolean2961: Boolean = false,
var aBoolean2993: Boolean = false,
var anInt3032: Int = 960,
var anInt2962: Int = 0,
var anInt3050: Int = 256,
var anInt3020: Int = 256,
var aBoolean2992: Boolean = false,
var anInt2975: Int = 0,
override var params: HashMap<Long, Any>? = null,
override var extras: Map<String, Any> = emptyMap()
) : Definition, Recolourable, ColorPalette, Parameterized, Extra {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as ObjectDefinition
if (id != other.id) return false
if (modelIds != null) {
if (other.modelIds == null) return false
if (!modelIds!!.contentEquals(other.modelIds!!)) return false
} else if (other.modelIds != null) return false
if (modelTypes != null) {
if (other.modelTypes == null) return false
if (!modelTypes!!.contentEquals(other.modelTypes!!)) return false
} else if (other.modelTypes != null) return false
if (name != other.name) return false
if (sizeX != other.sizeX) return false
if (sizeY != other.sizeY) return false
if (blocksSky != other.blocksSky) return false
if (solid != other.solid) return false
if (interactive != other.interactive) return false
if (contouredGround != other.contouredGround) return false
if (delayShading != other.delayShading) return false
if (offsetMultiplier != other.offsetMultiplier) return false
if (brightness != other.brightness) return false
if (!options.contentEquals(other.options)) return false
if (contrast != other.contrast) return false
if (originalColours != null) {
if (other.originalColours == null) return false
if (!originalColours!!.contentEquals(other.originalColours!!)) return false
} else if (other.originalColours != null) return false
if (modifiedColours != null) {
if (other.modifiedColours == null) return false
if (!modifiedColours!!.contentEquals(other.modifiedColours!!)) return false
} else if (other.modifiedColours != null) return false
if (originalTextureColours != null) {
if (other.originalTextureColours == null) return false
if (!originalTextureColours!!.contentEquals(other.originalTextureColours!!)) return false
} else if (other.originalTextureColours != null) return false
if (modifiedTextureColours != null) {
if (other.modifiedTextureColours == null) return false
if (!modifiedTextureColours!!.contentEquals(other.modifiedTextureColours!!)) return false
} else if (other.modifiedTextureColours != null) return false
if (recolourPalette != null) {
if (other.recolourPalette == null) return false
if (!recolourPalette!!.contentEquals(other.recolourPalette!!)) return false
} else if (other.recolourPalette != null) return false
if (mirrored != other.mirrored) return false
if (castsShadow != other.castsShadow) return false
if (modelSizeX != other.modelSizeX) return false
if (modelSizeZ != other.modelSizeZ) return false
if (modelSizeY != other.modelSizeY) return false
if (blockFlag != other.blockFlag) return false
if (offsetX != other.offsetX) return false
if (offsetZ != other.offsetZ) return false
if (offsetY != other.offsetY) return false
if (blocksLand != other.blocksLand) return false
if (ignoreOnRoute != other.ignoreOnRoute) return false
if (supportItems != other.supportItems) return false
if (varbitIndex != other.varbitIndex) return false
if (configId != other.configId) return false
if (configObjectIds != null) {
if (other.configObjectIds == null) return false
if (!configObjectIds!!.contentEquals(other.configObjectIds!!)) return false
} else if (other.configObjectIds != null) return false
if (anInt3015 != other.anInt3015) return false
if (anInt3012 != other.anInt3012) return false
if (anInt2989 != other.anInt2989) return false
if (anInt2971 != other.anInt2971) return false
if (anIntArray3036 != null) {
if (other.anIntArray3036 == null) return false
if (!anIntArray3036!!.contentEquals(other.anIntArray3036!!)) return false
} else if (other.anIntArray3036 != null) return false
if (anInt3023 != other.anInt3023) return false
if (hideMinimap != other.hideMinimap) return false
if (aBoolean2972 != other.aBoolean2972) return false
if (animateImmediately != other.animateImmediately) return false
if (isMembers != other.isMembers) return false
if (adjustMapSceneRotation != other.adjustMapSceneRotation) return false
if (hasAnimation != other.hasAnimation) return false
if (anInt2987 != other.anInt2987) return false
if (anInt3008 != other.anInt3008) return false
if (anInt3038 != other.anInt3038) return false
if (anInt3013 != other.anInt3013) return false
if (mapSceneRotation != other.mapSceneRotation) return false
if (mapscene != other.mapscene) return false
if (culling != other.culling) return false
if (anInt3024 != other.anInt3024) return false
if (invertMapScene != other.invertMapScene) return false
if (animations != null) {
if (other.animations == null) return false
if (!animations!!.contentEquals(other.animations!!)) return false
} else if (other.animations != null) return false
if (percents != null) {
if (other.percents == null) return false
if (!percents!!.contentEquals(other.percents!!)) return false
} else if (other.percents != null) return false
if (mapDefinitionId != other.mapDefinitionId) return false
if (anIntArray2981 != null) {
if (other.anIntArray2981 == null) return false
if (!anIntArray2981!!.contentEquals(other.anIntArray2981!!)) return false
} else if (other.anIntArray2981 != null) return false
if (aByte2974 != other.aByte2974) return false
if (aByte3045 != other.aByte3045) return false
if (aByte3052 != other.aByte3052) return false
if (aByte2960 != other.aByte2960) return false
if (anInt2964 != other.anInt2964) return false
if (anInt2963 != other.anInt2963) return false
if (anInt3018 != other.anInt3018) return false
if (anInt2983 != other.anInt2983) return false
if (aBoolean2961 != other.aBoolean2961) return false
if (aBoolean2993 != other.aBoolean2993) return false
if (anInt3032 != other.anInt3032) return false
if (anInt2962 != other.anInt2962) return false
if (anInt3050 != other.anInt3050) return false
if (anInt3020 != other.anInt3020) return false
if (aBoolean2992 != other.aBoolean2992) return false
if (anInt2975 != other.anInt2975) return false
if (params != other.params) return false
if (extras != other.extras) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + (modelIds?.contentHashCode() ?: 0)
result = 31 * result + (modelTypes?.contentHashCode() ?: 0)
result = 31 * result + name.hashCode()
result = 31 * result + sizeX
result = 31 * result + sizeY
result = 31 * result + blocksSky.hashCode()
result = 31 * result + solid
result = 31 * result + interactive
result = 31 * result + contouredGround
result = 31 * result + delayShading.hashCode()
result = 31 * result + offsetMultiplier
result = 31 * result + brightness
result = 31 * result + options.contentHashCode()
result = 31 * result + contrast
result = 31 * result + (originalColours?.contentHashCode() ?: 0)
result = 31 * result + (modifiedColours?.contentHashCode() ?: 0)
result = 31 * result + (originalTextureColours?.contentHashCode() ?: 0)
result = 31 * result + (modifiedTextureColours?.contentHashCode() ?: 0)
result = 31 * result + (recolourPalette?.contentHashCode() ?: 0)
result = 31 * result + mirrored.hashCode()
result = 31 * result + castsShadow.hashCode()
result = 31 * result + modelSizeX
result = 31 * result + modelSizeZ
result = 31 * result + modelSizeY
result = 31 * result + blockFlag
result = 31 * result + offsetX
result = 31 * result + offsetZ
result = 31 * result + offsetY
result = 31 * result + blocksLand.hashCode()
result = 31 * result + ignoreOnRoute.hashCode()
result = 31 * result + supportItems
result = 31 * result + varbitIndex
result = 31 * result + configId
result = 31 * result + (configObjectIds?.contentHashCode() ?: 0)
result = 31 * result + anInt3015
result = 31 * result + anInt3012
result = 31 * result + anInt2989
result = 31 * result + anInt2971
result = 31 * result + (anIntArray3036?.contentHashCode() ?: 0)
result = 31 * result + anInt3023
result = 31 * result + hideMinimap.hashCode()
result = 31 * result + aBoolean2972.hashCode()
result = 31 * result + animateImmediately.hashCode()
result = 31 * result + isMembers.hashCode()
result = 31 * result + adjustMapSceneRotation.hashCode()
result = 31 * result + hasAnimation.hashCode()
result = 31 * result + anInt2987
result = 31 * result + anInt3008
result = 31 * result + anInt3038
result = 31 * result + anInt3013
result = 31 * result + mapSceneRotation
result = 31 * result + mapscene
result = 31 * result + culling
result = 31 * result + anInt3024
result = 31 * result + invertMapScene.hashCode()
result = 31 * result + (animations?.contentHashCode() ?: 0)
result = 31 * result + (percents?.contentHashCode() ?: 0)
result = 31 * result + mapDefinitionId
result = 31 * result + (anIntArray2981?.contentHashCode() ?: 0)
result = 31 * result + aByte2974
result = 31 * result + aByte3045
result = 31 * result + aByte3052
result = 31 * result + aByte2960
result = 31 * result + anInt2964
result = 31 * result + anInt2963
result = 31 * result + anInt3018
result = 31 * result + anInt2983
result = 31 * result + aBoolean2961.hashCode()
result = 31 * result + aBoolean2993.hashCode()
result = 31 * result + anInt3032
result = 31 * result + anInt2962
result = 31 * result + anInt3050
result = 31 * result + anInt3020
result = 31 * result + aBoolean2992.hashCode()
result = 31 * result + anInt2975
result = 31 * result + (params?.hashCode() ?: 0)
result = 31 * result + extras.hashCode()
return result
}
}

View file

@ -0,0 +1,26 @@
package cacheops.cache.definition.data
import java.awt.Color
data class OverlayDefinition(
var color: Int = 0,
var texture: Int = -1,
var hideUnderlay: Boolean = true,
var blendColor: Int = -1,
var scale: Int = 128,
var blockShadow: Boolean = true,
var aByte0: Int = 8,
var blendTexture: Boolean = false,
var waterColor: Int = 1190717,
var waterScale: Int = 16,
var anInt0: Int = -1,
var waterIntensity: Int = 16
) {
override fun toString(): String {
return ""
}
fun getRGB(): Color {
return Color(color)
}
}

View file

@ -0,0 +1,36 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
@Suppress("ArrayInDataClass")
data class QuickChatOptionDefinition(
override var id: Int = -1,
var optionText: String? = null,
var quickReplyOptions: IntArray? = null,
var navigateChars: CharArray? = null,
var dynamicData: IntArray? = null,
var staticData: CharArray? = null
) : Definition {
fun getDynamicIndex(c: Char): Int {
if (dynamicData == null) {
return -1
}
for (i in dynamicData!!.indices) {
if (staticData!![i] == c) {
return dynamicData!![i]
}
}
return -1
}
fun getOption(c: Char): Int {
if (quickReplyOptions == null) {
return -1
}
for (i in quickReplyOptions!!.indices) {
if (navigateChars!![i] == c) {
return quickReplyOptions!![i]
}
}
return -1
}
}

View file

@ -0,0 +1,8 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
@Suppress("ArrayInDataClass")
data class SpriteDefinition(
override var id: Int = -1,
var sprites: Array<IndexedSprite>? = null
) : Definition

View file

@ -0,0 +1,25 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
data class TextureDefinition(
override var id: Int = -1,
var useTextureColour: Boolean = false,
var aBoolean1204: Boolean = false,
var aBoolean1205: Boolean = false,
var aByte1217: Byte = 0,
var aByte1225: Byte = 0,
var type: Byte = 0,
var aByte1213: Byte = 0,
var colour: Int = 0,
var aByte1211: Byte = 0,
var aByte1203: Byte = 0,
var aBoolean1222: Boolean = false,
var aBoolean1216: Boolean = false,
var aByte1207: Byte = 0,
var aBoolean1212: Boolean = false,
var aBoolean1210: Boolean = false,
var aBoolean1215: Boolean = false,
var anInt1202: Int = 0,
var anInt1206: Int = 0,
var anInt1226: Int = 0
) : Definition

View file

@ -0,0 +1,23 @@
package cacheops.cache.definition.data
import java.awt.Color
data class UnderlayDefinition(
var color: Int = 0,
var hue: Int = 0,
var saturation: Int = 0,
var lumiance: Int = 0,
var texture: Int = -1,
var scale: Int = 128,
var blockShadow: Boolean = true,
var blendHueMultiplier: Int = 0,
var blendHue: Int = 0
) {
override fun toString(): String {
return "[RAW(HSL): $color, BlendH: $blendHue, H: $hue, S: $saturation, L: $lumiance, Texture: $texture, Scale: $scale, Shadow: $blockShadow]"
}
fun getRGB(): Color {
return Color(color)
}
}

View file

@ -0,0 +1,9 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
data class VarBitDefinition(
override var id: Int = -1,
var index: Int = 0,
var leastSignificantBit: Int = 0,
var mostSignificantBit: Int = 0
) : Definition

View file

@ -0,0 +1,18 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
import java.util.*
data class WorldMapDefinition(
override var id: Int = -1,
var map: String = "",
var name: String = "",
var position: Int = -1,
var anInt9542: Int = -1,
var static: Boolean = false,
var anInt9547: Int = -1,
var sections: LinkedList<WorldMapSection>? = null,
var minX: Int = 12800,
var minY: Int = 12800,
var maxX: Int = 0,
var maxY: Int = 0
) : Definition

View file

@ -0,0 +1,6 @@
package cacheops.cache.definition.data
data class WorldMapIcon(
var id: Int = -1,
var position: Int = -1
)

View file

@ -0,0 +1,25 @@
package cacheops.cache.definition.data
import cacheops.cache.Definition
data class WorldMapIconDefinition(
override var id: Int = -1,
var icons: Array<WorldMapIcon> = emptyArray()
) : Definition {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as WorldMapIconDefinition
if (id != other.id) return false
if (!icons.contentEquals(other.icons)) return false
return true
}
override fun hashCode(): Int {
var result = id
result = 31 * result + icons.contentHashCode()
return result
}
}

View file

@ -0,0 +1,3 @@
package cacheops.cache.definition.data
data class WorldMapSection(val plane: Int, val minX: Int, val minY: Int, val maxX: Int, val maxY: Int, var startX: Int, var startY: Int, var endX: Int, var endY: Int)

View file

@ -0,0 +1,7 @@
package cacheops.cache.definition.decoder
class AtmosphereDecoder {
}

View file

@ -0,0 +1,95 @@
package cacheops.cache.definition.decoder
import cacheops.cache.Cache
import cacheops.cache.DefinitionDecoder
import cacheops.cache.buffer.read.BufferReader
import cacheops.cache.buffer.read.Reader
import cacheops.cache.definition.data.BlendedTextureDefinition
import const.Indices
class BlendedTextureDecoder(cache: Cache) : DefinitionDecoder<BlendedTextureDefinition>(cache, Indices.MATERIALS) {
companion object {
val blendedTextureDef = HashMap<Int, BlendedTextureDefinition>()
}
override fun create() = BlendedTextureDefinition()
var metricsCount = 0
override val last: Int
get() = metricsCount
init {
val data = getData(0, 0)
if (data != null) {
decode(BufferReader(data))
}
}
fun decode(buffer: Reader) {
metricsCount = buffer.readShort()
for (id in 0 until metricsCount) {
if (buffer.readUnsignedBoolean()) {
blendedTextureDef[id] = BlendedTextureDefinition(id = id)
}
}
for (texture in blendedTextureDef.values) { // J
texture.renderOnMap = !buffer.readUnsignedBoolean() // 0
}
for (texture in blendedTextureDef.values) {
buffer.readUnsignedBoolean() // 1
}
for (texture in blendedTextureDef.values) {
buffer.readUnsignedBoolean() // 1
}
for (texture in blendedTextureDef.values) {
buffer.readByte().toByte() // 1
}
for (texture in blendedTextureDef.values) {
buffer.readByte().toByte()
}
for (texture in blendedTextureDef.values) {
buffer.readByte().toByte()
}
for (texture in blendedTextureDef.values) {
buffer.readByte().toByte()
}
for (texture in blendedTextureDef.values) {
texture.blendedColor = buffer.readUnsignedShort()
println(texture.blendedColor)
}
for (texture in blendedTextureDef.values) {
buffer.readByte().toByte()
}
for (texture in blendedTextureDef.values) {
buffer.readByte().toByte()
}
for (texture in blendedTextureDef.values) {
buffer.readUnsignedBoolean()
}
for (texture in blendedTextureDef.values) {
buffer.readUnsignedBoolean()
}
for (texture in blendedTextureDef.values) {
buffer.readByte().toByte()
}
for (texture in blendedTextureDef.values) {
buffer.readUnsignedBoolean()
}
for (texture in blendedTextureDef.values) {
buffer.readUnsignedBoolean()
}
for (texture in blendedTextureDef.values) {
buffer.readUnsignedBoolean()
}
}
override fun clear() {
}
override fun BlendedTextureDefinition.read(opcode: Int, buffer: Reader) {
throw IllegalStateException("Shouldn't be used.")
}
}

View file

@ -0,0 +1,32 @@
package cacheops.cache.definition.decoder
import Rs2MapEditor
import cacheops.cache.definition.data.OverlayDefinition
import const.Archives
import const.Indices
import java.nio.ByteBuffer
object FloorOverlayConfiguration {
val cache = Rs2MapEditor.library.index(Indices.CONFIGURATION).archive(Archives.FLOOR_OVERLAYS)
var floorOverlays = hashMapOf<Int, OverlayDefinition>()
@JvmStatic
fun main(args: Array<String>) {
cache!!.files().forEach {
val buffer = ByteBuffer.wrap(it.data)
val definition = FloorOverlayDecoder().decode(buffer)
floorOverlays[it.id] = definition
}
}
fun init() {
cache!!.files().forEach {
val buffer = ByteBuffer.wrap(it.data)
val definition = FloorOverlayDecoder().decode(buffer)
floorOverlays[it.id] = definition
}
}
}

View file

@ -0,0 +1,157 @@
package cacheops.cache.definition.decoder
import cacheops.cache.definition.data.OverlayDefinition
import ext.medium
import ext.unsignedByte
import ext.unsignedShort
import java.nio.ByteBuffer
class FloorOverlayDecoder {
private var color = 0
private var texture = -1
private var hideUnderlay = true
private var blendColor = -1
private var anInt3081 = 0
private var scale = 128
private var blockShadow = true
private var aByte0 = 8
private var blendTexture = false
private var waterColor = 1190717
private var waterScale = 16
private var anInt0 = -1
private var waterIntensity = 16
fun decode(buffer: ByteBuffer): OverlayDefinition {
while (true) {
val opcode = buffer.unsignedByte()
if (opcode == 0) {
return OverlayDefinition(color, texture, hideUnderlay, blendColor, scale, blockShadow, aByte0, blendTexture, waterColor, waterScale, anInt0, waterIntensity)
}
decodeOverlayType(opcode, buffer)
}
}
/**
* Overlay Type Decoder
*
* Takes the standard params for a decoder, [opcode], [rsByteBuffer] and a [ID].
*
* Currently opcode [10] is unknown.
*/
private fun decodeOverlayType(opcode: Int, buffer: ByteBuffer) {
when (opcode) {
1 -> color = buffer.medium()//rgbToHsl(buffer.medium())
2 -> texture = buffer.unsignedByte()
3 -> {
texture = buffer.unsignedShort()
if (texture == 65535) {
texture = -1
}
}
5 -> hideUnderlay = false
7 -> blendColor = buffer.medium()//rgbToHsl(buffer.medium())
8 -> anInt3081
9 -> scale = buffer.unsignedShort()
10 -> blockShadow = false //Possibly blockShadow?
11 -> aByte0 = buffer.unsignedByte()
12 -> blendTexture = true
13 -> waterColor = buffer.medium()
14 -> waterScale = buffer.unsignedByte()
15 -> {
anInt0 = buffer.unsignedShort()
if (anInt0 == 65535) {
anInt0 = -1
}
}
16 -> waterIntensity = buffer.unsignedByte()
/* 14
* Handles how deep into water the player is able to see,
* seems to (but not confirmed) work in jumps of 2, so: "0, 2, 4, 6" etc.
* It seems any number equals to or less than 0, removes any visual
* effect obscuring the depth view. The first increment in order,
* being 2, blocks almost 100% of the view of the underwater map (UM).
*/
else -> println("Unhandled opcode $opcode")
}
}
private fun rgbToHsl(rgb: Int): Int {
if (rgb == 16711935) {
return -1
} else {
val d = (((0xff80ae and rgb) shr 16).toDouble() / 256.0)
val d_8_ = (((0xff6a and rgb) shr 8).toDouble() / 256.0)
val d_9_ = ((rgb and 0xff).toDouble() / 256.0)
var d_11_ = d
if (d_11_ > d_8_) {
d_11_ = d_8_
}
if (d_11_ > d_9_) {
d_11_ = d_9_
}
var d_12_ = d
if (d_8_ > d_12_) {
d_12_ = d_8_
}
if (d_12_ < d_9_) {
d_12_ = d_9_
}
var h = 0.0
var s = 0.0
val l = (d_12_ + d_11_) / 2.0
if (d_11_ != d_12_) {
if (l < 0.5) {
s = (-d_11_ + d_12_) / (d_12_ + d_11_)
}
if (l >= 0.5) {
s = (d_12_ - d_11_) / (-d_12_ + 2.0 - d_11_)
}
if (d_12_ == d) {
h = (d_8_ - d_9_) / (d_12_ - d_11_)
} else if (d_12_ == d_8_) {
h = (-d + d_9_) / (-d_11_ + d_12_) + 2.0
} else if (d_12_ == d_9_) {
h = (d - d_8_) / (d_12_ - d_11_) + 4.0
}
}
h /= 6.0
val hue = (h * 256.0).toInt()
var saturation = (s * 256.0).toInt()
var lumiance = (l * 256.0).toInt()
if (saturation >= 0) {
if (saturation > 255) {
saturation = 255
}
} else {
saturation = 0
}
if (lumiance >= 0) {
if (lumiance > 255) {
lumiance = 255
}
} else {
lumiance = 0
}
if (lumiance > 243) {
saturation = (saturation shr 4)
} else if (lumiance <= 217) {
if (lumiance > 192) {
saturation = (saturation shr 2)
} else if (lumiance > 179) {
saturation = (saturation shr 1)
}
} else {
saturation = (saturation shr 3)
}
return ((((hue and 0xff) shr 2) shl 10) + ((saturation shr 5) shl 7) + (lumiance shr 1))
}
}
}

View file

@ -0,0 +1,33 @@
package cacheops.cache.definition.decoder
import Rs2MapEditor
import cacheops.cache.definition.data.UnderlayDefinition
import const.Archives
import const.Indices
import java.nio.ByteBuffer
object FloorUnderlayConfiguration {
val cache = Rs2MapEditor.library.index(Indices.CONFIGURATION).archive(Archives.FLOOR_UNDERLAYS)
var floorUnderlays = hashMapOf<Int, UnderlayDefinition>()
@JvmStatic
fun main(args: Array<String>) {
cache!!.files().forEach {
val buffer = ByteBuffer.wrap(it.data)
val definition = FloorUnderlayDecoder().decode(buffer)
floorUnderlays[it.id] = definition
}
}
fun init() {
cache!!.files().forEach {
val buffer = ByteBuffer.wrap(it.data)
val definition = FloorUnderlayDecoder().decode(buffer)
floorUnderlays[it.id] = definition
//println(definition.toString())
}
}
}

View file

@ -0,0 +1,132 @@
package cacheops.cache.definition.decoder
import cacheops.cache.definition.data.UnderlayDefinition
import ext.medium
import ext.unsignedByte
import ext.unsignedShort
import java.nio.ByteBuffer
class FloorUnderlayDecoder {
private var color: Int = 0
private var hsl16: Int = 0
private var blendHueMultiplier: Int = 0
private var hue: Int = 0
private var saturation: Int = 0
private var lumiance: Int = 0
private var textureID = -1
private var textureSize = 128
private var blockShadow = true
private var blendHue: Int = 0
fun decode(buffer: ByteBuffer): UnderlayDefinition {
while (true) {
val opcode = buffer.unsignedByte()
if (opcode == 0) {
return UnderlayDefinition(color, hue, saturation, lumiance, textureID, textureSize, blockShadow, blendHueMultiplier, blendHue)
}
decodeUnderlayType(opcode, buffer)
}
}
private fun decodeUnderlayType(opcode: Int, buffer: ByteBuffer) {
when (opcode) {
1 -> {
color = buffer.medium()
intToColor(color)
}
2 -> {
textureID = buffer.unsignedShort()
if (textureID == 65535) {
textureID = -1
}
}
3 -> {
textureSize = buffer.unsignedShort()
}
4 -> {
blockShadow = false
}
}
}
private fun intToColor(rgb: Int) {
val r: Double = (rgb shr 16 and 0xff) / 256.0
val g: Double = (rgb shr 8 and 0xff) / 256.0
val b: Double = (rgb and 0xff) / 256.0
var min = r
if (g < min) {
min = g
}
if (b < min) {
min = b
}
var max = r
if (g > max) {
max = g
}
if (b > max) {
max = b
}
var h = 0.0
var s = 0.0
val l = (min + max) / 2.0
if (min != max) {
if (l < 0.5) {
s = (max - min) / (max + min)
}
if (l >= 0.5) {
s = (max - min) / (2.0 - max - min)
}
if (r == max) {
h = (g - b) / (max - min)
} else if (g == max) {
h = 2.0 + (b - r) / (max - min)
} else if (b == max) {
h = 4.0 + (r - g) / (max - min)
}
}
h /= 6.0
hue = (h * 256.0).toInt()
saturation = (s * 256.0).toInt()
lumiance = (l * 256.0).toInt()
if (saturation < 0) {
saturation = 0
} else if (saturation > 255) {
saturation = 255
}
if (lumiance < 0) {
lumiance = 0
} else if (lumiance > 255) {
lumiance = 255
}
blendHueMultiplier = if (l > 0.5) {
((1.0 - l) * s * 512.0).toInt()
} else {
(l * s * 512.0).toInt()
}
if (blendHueMultiplier < 1) {
blendHueMultiplier = 1
}
blendHue = (h * blendHueMultiplier).toInt()
hsl16 = hsl24to16(hue, saturation, lumiance)
}
private fun hsl24to16(h: Int, s: Int, l: Int): Int {
var s = s
if (l > 179) {
s /= 2
}
if (l > 192) {
s /= 2
}
if (l > 217) {
s /= 2
}
if (l > 243) {
s /= 2
}
return (h / (4 shl 10)) + (s / (32 shl 7)) + l / 2
}
}

View file

@ -0,0 +1,53 @@
package cacheops.cache.definition.decoder
import Rs2MapEditor
import cacheops.cache.definition.data.ItemDefinition
import const.cache
import ext.unsignedShort
import java.nio.ByteBuffer
val itemDecoder = ItemDecoder(cache)
class GroundItemDecoder {
fun decode(data: ByteArray): ArrayList<Item> {
val buffer = ByteBuffer.wrap(data)
val list = ArrayList<Item>()
while (buffer.hasRemaining()) {
val coords = buffer.unsignedShort()
val lz = coords shr 14
val lx = (coords shr 7) and 0x3f
val ly = coords and 0x3f
val itemID = buffer.unsignedShort()
val respawnTime = buffer.unsignedShort()
val amount = buffer.int
list.add(Item(itemID, lx, ly, lz, respawnTime, amount))
}
return list
}
}
object GroundItemSpawnParser {
fun parseItemSpawns(regionId: Int): ArrayList<Item> {
val x = (regionId shr 8) and 0xFF
val y = regionId and 0xFF
val groundItemData = Rs2MapEditor.library.data(5, "i${x}_${y}")
if (groundItemData != null && groundItemData.isNotEmpty()) {
return GroundItemDecoder().decode(groundItemData)
}
return ArrayList()
}
}
class Item(val id: Int, val x: Int, val y: Int, val plane: Int, val respawnTime: Int, val amount: Int) {
val definition: ItemDefinition = itemDecoder.forId(id)
}

View file

@ -0,0 +1,251 @@
package cacheops.cache.definition.decoder
import cacheops.cache.Cache
import cacheops.cache.DefinitionDecoder
import cacheops.cache.buffer.read.Reader
import cacheops.cache.definition.data.ItemDefinition
import const.Indices
class ItemDecoder(cache: Cache) : DefinitionDecoder<ItemDefinition>(cache, Indices.CONFIGURATION_ITEMS) {
companion object {
val DEFINITIONS = HashMap<Int, ItemDefinition>()
}
override fun create() = ItemDefinition()
override fun getFile(id: Int) = id and 0xff
override fun getArchive(id: Int) = id ushr 8
override fun readData(id: Int): ItemDefinition? {
return super.readData(id)
}
fun forId(id : Int): ItemDefinition {
if(DEFINITIONS[id] != null) return DEFINITIONS[id]!!
val def = readData(id)
DEFINITIONS[id] = def ?: ItemDefinition(id, 0, "null")
return DEFINITIONS[id]!!
}
override fun ItemDefinition.read(opcode: Int, buffer: Reader) {
when (opcode) {
1 -> modelId = buffer.readShort()
2 -> name = buffer.readString()
4 -> spriteScale = buffer.readShort()
5 -> spritePitch = buffer.readShort()
6 -> spriteCameraRoll = buffer.readShort()
7 -> {
spriteTranslateX = buffer.readShort()
if (spriteTranslateX > 32767) {
spriteTranslateX -= 65536
}
}
8 -> {
spriteTranslateY = buffer.readShort()
if (spriteTranslateY > 32767) {
spriteTranslateY -= 65536
}
}
11 -> stackable = 1
12 -> cost = buffer.readInt()
16 -> members = true
18 -> multiStackSize = buffer.readShort()
23 -> primaryMaleModel = buffer.readUnsignedShort()
24 -> secondaryMaleModel = buffer.readUnsignedShort()
25 -> primaryFemaleModel = buffer.readUnsignedShort()
26 -> secondaryFemaleModel = buffer.readUnsignedShort()
in 30..34 -> floorOptions[opcode - 30] = buffer.readString()
in 35..39 -> options[opcode - 35] = buffer.readString()
40 -> readColours(buffer)
41 -> readTextures(buffer)
42 -> readColourPalette(buffer)
65 -> exchangeable = true
78 -> tertiaryMaleModel = buffer.readShort()
79 -> tertiaryFemaleModel = buffer.readShort()
90 -> primaryMaleDialogueHead = buffer.readShort()
91 -> primaryFemaleDialogueHead = buffer.readShort()
92 -> secondaryMaleDialogueHead = buffer.readShort()
93 -> secondaryFemaleDialogueHead = buffer.readShort()
95 -> spriteCameraYaw = buffer.readShort()
96 -> dummyItem = buffer.readUnsignedByte()
97 -> noteId = buffer.readShort()
98 -> notedTemplateId = buffer.readShort()
in 100..109 -> {
if (stackIds == null) {
stackAmounts = IntArray(10)
stackIds = IntArray(10)
}
stackIds!![opcode - 100] = buffer.readShort()
stackAmounts!![opcode - 100] = buffer.readShort()
}
110 -> floorScaleX = buffer.readShort()
111 -> floorScaleZ = buffer.readShort()
112 -> floorScaleY = buffer.readShort()
113 -> ambience = buffer.readByte()
114 -> diffusion = buffer.readByte() * 5
115 -> team = buffer.readUnsignedByte()
121 -> lendId = buffer.readShort()
122 -> lendTemplateId = buffer.readShort()
125 -> {
maleWieldX = buffer.readByte() shl 2
maleWieldZ = buffer.readByte() shl 2
maleWieldY = buffer.readByte() shl 2
}
126 -> {
femaleWieldX = buffer.readByte() shl 2
femaleWieldZ = buffer.readByte() shl 2
femaleWieldY = buffer.readByte() shl 2
}
127 -> {
primaryCursorOpcode = buffer.readUnsignedByte()
primaryCursor = buffer.readShort()
}
128 -> {
secondaryCursorOpcode = buffer.readUnsignedByte()
secondaryCursor = buffer.readShort()
}
129 -> {
primaryInterfaceCursorOpcode = buffer.readUnsignedByte()
primaryInterfaceCursor = buffer.readShort()
}
130 -> {
secondaryInterfaceCursorOpcode = buffer.readUnsignedByte()
secondaryInterfaceCursor = buffer.readShort()
}
132 -> {
val length = buffer.readUnsignedByte()
campaigns = IntArray(length)
repeat(length) { count ->
campaigns!![count] = buffer.readShort()
}
}
134 -> pickSizeShift = buffer.readUnsignedByte()
139 -> singleNoteId = buffer.readShort()
140 -> singleNoteTemplateId = buffer.readShort()
249 -> readParameters(buffer)
}
}
override fun ItemDefinition.changeValues() {
if (notedTemplateId != -1) {
toNote(getOrNull(notedTemplateId), getOrNull(noteId))
}
if (lendTemplateId != -1) {
toLend(getOrNull(lendId), getOrNull(lendTemplateId))
}
if (singleNoteTemplateId != -1) {
toSingleNote(getOrNull(singleNoteTemplateId), getOrNull(singleNoteId))
}
}
fun ItemDefinition.toLend(item: ItemDefinition?, template: ItemDefinition?) {
if (item == null || template == null) {
return
}
modifiedColours = item.modifiedColours
primaryMaleDialogueHead = item.primaryMaleDialogueHead
secondaryMaleDialogueHead = item.secondaryMaleDialogueHead
tertiaryMaleModel = item.tertiaryMaleModel
team = item.team
params = item.params
members = item.members
modifiedTextureColours = item.modifiedTextureColours
maleWieldZ = item.maleWieldZ
secondaryFemaleModel = item.secondaryFemaleModel
spriteCameraYaw = template.spriteCameraYaw
floorOptions = item.floorOptions
secondaryFemaleDialogueHead = item.secondaryFemaleDialogueHead
recolourPalette = item.recolourPalette
femaleWieldZ = item.femaleWieldZ
spritePitch = template.spritePitch
primaryFemaleModel = item.primaryFemaleModel
modelId = template.modelId
options = arrayOfNulls(5)
spriteCameraRoll = template.spriteCameraRoll
spriteTranslateY = template.spriteTranslateY
originalTextureColours = item.originalTextureColours
femaleWieldX = item.femaleWieldX
secondaryMaleModel = item.secondaryMaleModel
cost = 0
maleWieldY = item.maleWieldY
originalColours = item.originalColours
spriteTranslateX = template.spriteTranslateX
femaleWieldY = item.femaleWieldY
primaryFemaleDialogueHead = item.primaryFemaleDialogueHead
spriteScale = template.spriteScale
name = item.name
tertiaryFemaleModel = item.tertiaryFemaleModel
primaryMaleModel = item.primaryMaleModel
maleWieldX = item.maleWieldX
System.arraycopy(item.options, 0, options, 0, 4)
options[4] = "Discard"
}
fun ItemDefinition.toNote(template: ItemDefinition?, item: ItemDefinition?) {
if (item == null || template == null) {
return
}
spriteTranslateY = template.spriteTranslateY
originalColours = template.originalColours
cost = item.cost
name = item.name
modifiedTextureColours = template.modifiedTextureColours
spriteCameraRoll = template.spriteCameraRoll
spriteCameraYaw = template.spriteCameraYaw
originalTextureColours = template.originalTextureColours
modelId = template.modelId
spriteScale = template.spriteScale
recolourPalette = template.recolourPalette
stackable = 1
spritePitch = template.spritePitch
spriteTranslateX = template.spriteTranslateX
members = item.members
modifiedColours = template.modifiedColours
}
fun ItemDefinition.toSingleNote(template: ItemDefinition?, item: ItemDefinition?) {
if (item == null || template == null) {
return
}
cost = 0
tertiaryMaleModel = item.tertiaryMaleModel
stackable = item.stackable
members = item.members
recolourPalette = item.recolourPalette
spriteTranslateY = template.spriteTranslateY
team = item.team
secondaryMaleModel = item.secondaryMaleModel
options = arrayOfNulls(5)
floorOptions = item.floorOptions
maleWieldZ = item.maleWieldZ
primaryMaleDialogueHead = item.primaryMaleDialogueHead
femaleWieldZ = item.femaleWieldZ
name = item.name
spriteScale = template.spriteScale
originalColours = item.originalColours
secondaryFemaleDialogueHead = item.secondaryFemaleDialogueHead
params = item.params
primaryFemaleModel = item.primaryFemaleModel
spritePitch = template.spritePitch
spriteCameraRoll = template.spriteCameraRoll
femaleWieldX = item.femaleWieldX
secondaryMaleDialogueHead = item.secondaryMaleDialogueHead
tertiaryFemaleModel = item.tertiaryFemaleModel
modifiedTextureColours = item.modifiedTextureColours
maleWieldX = item.maleWieldX
primaryFemaleDialogueHead = item.primaryFemaleDialogueHead
modelId = template.modelId
modifiedColours = item.modifiedColours
secondaryFemaleModel = item.secondaryFemaleModel
spriteTranslateX = template.spriteTranslateX
spriteCameraYaw = template.spriteCameraYaw
primaryMaleModel = item.primaryMaleModel
femaleWieldY = item.femaleWieldY
maleWieldY = item.maleWieldY
originalTextureColours = item.originalTextureColours
System.arraycopy(item.options, 0, options, 0, 4)
options[4] = "Discard"
}
}

View file

@ -0,0 +1,48 @@
package cacheops.cache.definition.decoder
import cacheops.cache.definition.data.MapDefinition
import cacheops.cache.definition.data.MapTile
import ext.unsignedByte
import java.nio.ByteBuffer
class MapTileDecoder {
fun readLoop(definition: MapDefinition, buffer: ByteBuffer): ByteArray {
for (plane in 0 until 4) {
for (localX in 0 until 64) {
for (localY in 0 until 64) {
var height = 0
var attrOpcode = 0
var overlayPath = 0
var overlayRotation = 0
var overlayId = 0
var settings = 0
var underlayId = 0
loop@ while (true) {
val config = buffer.unsignedByte()
if (config == 0) {
break@loop
} else if (config == 1) {
height = buffer.unsignedByte()
break@loop
} else if (config <= 49) {
attrOpcode = config
overlayId = buffer.unsignedByte()
overlayPath = (config - 2) / 4
overlayRotation = 3 and (config - 2)
} else if (config <= 81) {
settings = config - 49
} else {
underlayId = (config - 81) and 0xff
}
}
if (height != 0 || attrOpcode != 0 || overlayPath != 0 || overlayRotation != 0 || overlayId != 0 || settings != 0 || underlayId != 0) {
definition.setTile(localX, localY, plane, MapTile(height, attrOpcode, if(overlayId == 42) 0 else overlayId, overlayPath, overlayRotation, settings, underlayId))
}
}
}
}
return buffer.array().copyOfRange(buffer.position(), buffer.capacity())
}
}

View file

@ -0,0 +1,55 @@
package cacheops.cache.definition.decoder
import Rs2MapEditor
import cacheops.cache.definition.data.MapDefinition
import java.nio.ByteBuffer
object MapTileParser {
val definition = MapDefinition()
lateinit var atmosphereDataTail: ByteArray
@JvmStatic
fun main(args: Array<String>) {
val region = 12850
val baseX = ((region shr 8) shl 6)
val baseY = ((region and 0xFF) shl 6)
val x = (region shr 8) and 0xFF
val y = region and 0xFF
val mapData = Rs2MapEditor.library.data(5,"m${x}_${y}")
MapTileDecoder().readLoop(definition, ByteBuffer.wrap(mapData))
for (lclX in 0 until 64) {
for (lclY in 0 until 64) {
println(definition.getTile(lclX,lclY,0).underlayId)
}
}
}
fun init() {
definition.objects.clear()
definition.tiles.clear()
val region = Rs2MapEditor.region
val baseX = ((region shr 8) shl 6)
val baseY = ((region and 0xFF) shl 6)
val x = (region shr 8) and 0xFF
val y = region and 0xFF
val mapData = Rs2MapEditor.library.data(5,"m${x}_${y}")
println(mapData!!.size)
atmosphereDataTail = MapTileDecoder().readLoop(definition, ByteBuffer.wrap(mapData))
}
fun coordinateX(x: Int): Int {
val baseX = ((Rs2MapEditor.region shr 8) shl 6)
return x + baseX
}
fun coordinateY(y: Int): Int {
val baseY = ((Rs2MapEditor.region and 0xFF) shl 6)
return y + baseY
}
}

View file

@ -0,0 +1,194 @@
package cacheops.cache.definition.decoder
import cacheops.cache.Cache
import cacheops.cache.DefinitionDecoder
import cacheops.cache.buffer.read.Reader
import cacheops.cache.definition.data.NPCDefinition
import const.Indices
class NPCDecoder(cache: Cache, val member: Boolean) : DefinitionDecoder<NPCDefinition>(cache, Indices.CONFIGURATION_NPCS) {
companion object {
val DEFINITIONS = HashMap<Int, NPCDefinition>()
}
override fun create() = NPCDefinition()
override fun getFile(id: Int) = id and 0x7f
override fun getArchive(id: Int) = id ushr 7
override fun readData(id: Int): NPCDefinition? {
return super.readData(id)
}
fun forId(id : Int): NPCDefinition {
if(DEFINITIONS[id] != null) return DEFINITIONS[id]!!
val def = readData(id)
DEFINITIONS[id] = def ?: NPCDefinition(id,null,"null")
return DEFINITIONS[id]!!
}
override fun NPCDefinition.read(opcode: Int, buffer: Reader) {
when (opcode) {
1 -> {
val length = buffer.readUnsignedByte()
modelIds = IntArray(length)
repeat(length) { count ->
modelIds!![count] = buffer.readShort()
if (modelIds!![count] == 65535) {
modelIds!![count] = -1
}
}
}
2 -> name = buffer.readString()
12 -> size = buffer.readUnsignedByte()
in 30..34 -> options[-30 + opcode] = buffer.readString()
40 -> readColours(buffer)
41 -> readTextures(buffer)
42 -> {
val length = buffer.readUnsignedByte()
recolourPalette = ByteArray(length)
repeat(length) { count ->
recolourPalette!![count] = buffer.readByte().toByte()
}
}
60 -> {
val length = buffer.readUnsignedByte()
dialogueModels = IntArray(length)
repeat(length) { count ->
dialogueModels!![count] = buffer.readShort()
}
}
93 -> drawMinimapDot = false
95 -> combat = buffer.readShort()
97 -> scaleXY = buffer.readShort()
98 -> scaleZ = buffer.readShort()
99 -> priorityRender = true
100 -> lightModifier = buffer.readByte()
101 -> shadowModifier = 5 * buffer.readByte()
102 -> headIcon = buffer.readShort()
103 -> rotation = buffer.readShort()
106, 118 -> {
varbit = buffer.readShort()
if (varbit == 65535) {
varbit = -1
}
varp = buffer.readShort()
if (varp == 65535) {
varp = -1
}
var last = -1
if (opcode == 118) {
last = buffer.readShort()
if (last == 65535) {
last = -1
}
}
val count = buffer.readUnsignedByte()
morphs = IntArray(count + 2)
for (index in 0..count) {
morphs!![index] = buffer.readShort()
if (morphs!![index] == 65535) {
morphs!![index] = -1
}
}
morphs!![count + 1] = last
}
107 -> clickable = false
109 -> slowWalk = false
111 -> animateIdle = false
113 -> {
primaryShadowColour = buffer.readShort().toShort()
secondaryShadowColour = buffer.readShort().toShort()
}
114 -> {
primaryShadowModifier = buffer.readByte().toByte()
secondaryShadowModifier = buffer.readByte().toByte()
}
119 -> walkMask = buffer.readByte().toByte()
121 -> {
translations = arrayOfNulls(modelIds!!.size)
val length = buffer.readUnsignedByte()
repeat(length) {
val index = buffer.readUnsignedByte()
translations!![index] = intArrayOf(
buffer.readByte(),
buffer.readByte(),
buffer.readByte()
)
}
}
122 -> hitbarSprite = buffer.readShort()
123 -> height = buffer.readShort()
125 -> respawnDirection = buffer.readByte().toByte()
127 -> renderEmote = buffer.readShort()
128 -> buffer.readUnsignedByte()
134 -> {
idleSound = buffer.readShort()
if (idleSound == 65535) {
idleSound = -1
}
crawlSound = buffer.readShort()
if (crawlSound == 65535) {
crawlSound = -1
}
walkSound = buffer.readShort()
if (walkSound == 65535) {
walkSound = -1
}
runSound = buffer.readShort()
if (runSound == 65535) {
runSound = -1
}
soundDistance = buffer.readUnsignedByte()
}
135 -> {
primaryCursorOp = buffer.readUnsignedByte()
primaryCursor = buffer.readShort()
}
136 -> {
secondaryCursorOp = buffer.readUnsignedByte()
secondaryCursor = buffer.readShort()
}
137 -> attackCursor = buffer.readShort()
138 -> armyIcon = buffer.readShort()
139 -> spriteId = buffer.readShort()
140 -> ambientSoundVolume = buffer.readUnsignedByte()
141 -> visiblePriority = true
142 -> mapFunction = buffer.readShort()
143 -> invisiblePriority = true
in 150..154 -> {
options[opcode - 150] = buffer.readString()
if (!member) {
options[opcode - 150] = null
}
}
155 -> {
hue = buffer.readByte().toByte()
saturation = buffer.readByte().toByte()
lightness = buffer.readByte().toByte()
opacity = buffer.readByte().toByte()
}
158 -> mainOptionIndex = 1.toByte()
159 -> mainOptionIndex = 0.toByte()
160 -> {
val length = buffer.readUnsignedByte()
campaigns = IntArray(length)
repeat(length) { count ->
campaigns!![count] = buffer.readShort()
}
}
162 -> aBoolean2883 = true
163 -> anInt2803 = buffer.readUnsignedByte()
164 -> {
anInt2844 = buffer.readShort()
anInt2852 = buffer.readShort()
}
165 -> anInt2831 = buffer.readUnsignedByte()
168 -> anInt2862 = buffer.readUnsignedByte()
249 -> readParameters(buffer)
}
}
}

View file

@ -0,0 +1,48 @@
package cacheops.cache.definition.decoder
import Rs2MapEditor
import cacheops.cache.definition.data.NPCDefinition
import const.cache
import ext.unsignedShort
import java.nio.ByteBuffer
val decoder = NPCDecoder(cache, true)
class NPCSpawnDecoder {
fun decode(data: ByteArray): ArrayList<NPC> {
val buffer = ByteBuffer.wrap(data)
val list = ArrayList<NPC>()
while (buffer.hasRemaining()) {
val coords = buffer.unsignedShort()
val lz = coords shr 14
val lx = (coords shr 7) and 0x3f
val ly = coords and 0x3f
val npcID = buffer.unsignedShort()
list.add(NPC(npcID, lx, ly, lz))
}
return list
}
}
object NPCSpawnParser {
fun parseNPCSpawns(regionId: Int): ArrayList<NPC> {
val x = (regionId shr 8) and 0xFF
val y = regionId and 0xFF
val npcSpawnData = Rs2MapEditor.library.data(5, "n${x}_${y}")
if (npcSpawnData != null && npcSpawnData.isNotEmpty()) {
return NPCSpawnDecoder().decode(npcSpawnData)
}
return ArrayList()
}
}
class NPC(val id: Int, val x: Int, val y: Int, val plane: Int) {
val definition: NPCDefinition = decoder.forId(id)
}

View file

@ -0,0 +1,237 @@
package cacheops.cache.definition.decoder
import cacheops.cache.Cache
import cacheops.cache.DefinitionDecoder
import cacheops.cache.buffer.read.Reader
import cacheops.cache.definition.data.ObjectDefinition
import const.Indices
open class ObjectDecoder(cache: Cache, val member: Boolean, val configReplace: Boolean) : DefinitionDecoder<ObjectDefinition>(cache, Indices.CONFIGURATION_OBJECT) {
val DEFINITIONS = HashMap<Int,ObjectDefinition>()
fun forId(id: Int): ObjectDefinition{
if(DEFINITIONS[id] != null) return DEFINITIONS[id]!!
val def = readData(id)
DEFINITIONS[id] = def ?: ObjectDefinition(id,null,null,"null")
return DEFINITIONS[id]!!
}
override fun create() = ObjectDefinition()
override fun getFile(id: Int) = id and 0xff
override fun getArchive(id: Int) = id ushr 8
override fun readData(id: Int): ObjectDefinition? {
val def = super.readData(id)
val replacement = def?.getReplacementId() ?: return def
return super.readData(replacement)
}
private fun ObjectDefinition.getReplacementId(): Int? {
if (!configReplace) {
return null
}
val configIndex = 0
val configs = configObjectIds ?: return null
val config = if (configIndex < 0 || (configIndex >= configs.size - 1 || configs[configIndex] == -1)) {
configs[configs.size - 1]
} else {
configs.getOrNull(configIndex)
}
return if (config != -1) config else null
}
override fun ObjectDefinition.read(opcode: Int, buffer: Reader) {
when (opcode) {
1 -> {
val count = buffer.readUnsignedByte()
if (count > 0) {
if (modelIds == null) {
modelIds = IntArray(count)
modelTypes = IntArray(count)
var i = 0
while (count > i) {
modelIds!![i] = buffer.readUnsignedShort()
modelTypes!![i] = buffer.readUnsignedByte()
i++
}
} else {
buffer.position(buffer.position() + count * 3)
}
}
}
2 -> name = buffer.readString()
5 -> {
val i_30_ = buffer.readUnsignedByte()
if (i_30_ > 0) {
if (modelIds == null) {
modelIds = IntArray(i_30_)
modelTypes = null
var i_31_ = 0
while (i_30_ > i_31_) {
modelIds!![i_31_] = buffer.readUnsignedShort()
i_31_++
}
} else {
buffer.position(buffer.position() + i_30_ * 2)
}
}
}
14 -> sizeX = buffer.readUnsignedByte()
15 -> sizeY = buffer.readUnsignedByte()
17 -> {
blocksSky = false
solid = 0
}
18 -> blocksSky = false
19 -> interactive = buffer.readUnsignedByte()
21 -> contouredGround = 1
22 -> delayShading = true
23 -> culling = 1
24 -> {
val length = buffer.readUnsignedShort()
if (length != 65535) {
animations = intArrayOf(length)
}
}
27 -> solid = 1
28 -> offsetMultiplier = buffer.readUnsignedByte()
29 -> brightness = buffer.readByte()
in 30..34 -> options[opcode - 30] = buffer.readString()
39 -> contrast = buffer.readByte() * 5
40 -> readColours(buffer)
41 -> readTextures(buffer)
42 -> readColourPalette(buffer)
62 -> mirrored = true
64 -> castsShadow = false
65 -> modelSizeX = buffer.readUnsignedShort()
66 -> modelSizeZ = buffer.readUnsignedShort()
67 -> modelSizeY = buffer.readUnsignedShort()
69 -> blockFlag = buffer.readUnsignedByte()
70 -> offsetX = buffer.readUnsignedShort() shl 2
71 -> offsetZ = buffer.readUnsignedShort() shl 2
72 -> offsetY = buffer.readUnsignedShort() shl 2
73 -> blocksLand = true
74 -> ignoreOnRoute = true
75 -> supportItems = buffer.readUnsignedByte()
77, 92 -> {
varbitIndex = buffer.readUnsignedShort()
if (varbitIndex == 65535) {
varbitIndex = -1
}
configId = buffer.readUnsignedShort()
if (configId == 65535) {
configId = -1
}
var last = -1
if (opcode == 92) {
last = buffer.readUnsignedShort()
if (last == 65535) {
last = -1
}
}
val length = buffer.readUnsignedByte()
configObjectIds = IntArray(length + 2)
for (count in 0..length) {
configObjectIds!![count] = buffer.readUnsignedShort()
if (configObjectIds!![count] == 65535) {
configObjectIds!![count] = -1
}
}
configObjectIds!![length + 1] = last
}
78 -> {
anInt3015 = buffer.readUnsignedShort()
anInt3012 = buffer.readUnsignedByte()
}
79 -> {
anInt2989 = buffer.readUnsignedShort()
anInt2971 = buffer.readUnsignedShort()
anInt3012 = buffer.readUnsignedByte()
val length = buffer.readUnsignedByte()
anIntArray3036 = IntArray(length)
repeat(length) { count ->
anIntArray3036!![count] = buffer.readUnsignedShort()
}
}
81 -> {
contouredGround = 2.toByte()
anInt3023 = buffer.readUnsignedByte() * 256
}
82 -> hideMinimap = true
88 -> aBoolean2972 = false
89 -> animateImmediately = false
90 -> aBoolean1502 = true
91 -> isMembers = true
93 -> {
contouredGround = 3
anInt3023 = buffer.readUnsignedShort()
}
94 -> contouredGround = 4
95 -> {
contouredGround = 5
}
96 -> aBoolean1507 = true
97 -> adjustMapSceneRotation = true
98 -> hasAnimation = true
99 -> {
anInt2987 = buffer.readUnsignedByte()
anInt3008 = buffer.readUnsignedShort()
}
100 -> {
anInt3038 = buffer.readUnsignedByte()
anInt3013 = buffer.readUnsignedShort()
}
101 -> mapSceneRotation = buffer.readUnsignedByte()
102 -> mapscene = buffer.readUnsignedShort()
103 -> culling = 0
104 -> anInt3024 = buffer.readUnsignedByte()
105 -> invertMapScene = true
106 -> {
val length = buffer.readUnsignedByte()
var total = 0
animations = IntArray(length)
percents = IntArray(length)
repeat(length) { count ->
animations!![count] = buffer.readUnsignedShort()
if (animations!![count] == 65535) {
animations!![count] = -1
}
percents!![count] = buffer.readUnsignedByte()
total += percents!![count]
}
repeat(length) { count ->
percents!![count] = 65535 * percents!![count] / total
}
}
107 -> mapDefinitionId = buffer.readUnsignedShort()
in 150..154 -> {
options[-150 + opcode] = buffer.readString()
if (!member) {
options[-150 + opcode] = null
}
}
160 -> {
val length = buffer.readUnsignedByte()
anIntArray2981 = IntArray(length)
repeat(length) { count ->
anIntArray2981!![count] = buffer.readUnsignedShort()
}
}
249 -> readParameters(buffer)
}
}
companion object {
private fun skip(buffer: Reader) {
val length = buffer.readUnsignedByte()
repeat(length) {
buffer.skip(1)
val amount = buffer.readUnsignedByte()
buffer.skip(amount * 2)
}
}
}
}

View file

@ -0,0 +1,59 @@
package cacheops.cache.definition.decoder
import Rs2MapEditor
import cacheops.cache.definition.data.ObjectDefinition
import const.cache
import ext.getBigSmart
import ext.getSmart
import java.nio.ByteBuffer
val objectDecoder = ObjectDecoder(cache, true, false)
object TileSceneryParser {
fun parseRegion(id: Int): ArrayList<Scenery>{
if(XteaKeys.XTEAS.isEmpty()){
XteaKeys.load()
}
val regionX = (id shr 8) and 0xFF;
val regionY = id and 0xFF;
val data = Rs2MapEditor.library.data(5, "l${regionX}_${regionY}",XteaKeys.get(id))
return if(data != null) decode(ByteBuffer.wrap(data))
else ArrayList()
}
private fun decode(data: ByteBuffer): ArrayList<Scenery>{
val list = ArrayList<Scenery>()
var objectId = -1
while (true) {
var offset: Int = data.getBigSmart()
if (offset == 0) {
break
}
objectId += offset
var location = 0
while (true) {
offset = data.getSmart()
if (offset == 0) {
break
}
location += offset - 1
val y = location and 0x3f
val x = (location shr 6) and 0x3f
val configuration: Int = data.get().toInt() and 0xFF
val rotation = configuration and 0x3
val type = configuration shr 2
val z = location shr 12
list.add(Scenery(objectId,x,y,z,rotation,type))
}
}
return list
}
}
class Scenery(val id: Int, val x: Int, val y: Int, val plane: Int, val rotation: Int, val type: Int){
val definition = objectDecoder.forId(id)
}

View file

@ -0,0 +1,33 @@
package cacheops.cache.definition.decoder
import const.xteaJson
import org.json.simple.JSONArray
import org.json.simple.JSONObject
import org.json.simple.parser.JSONParser
import java.io.FileReader
object XteaKeys {
val XTEAS = HashMap<Int,IntArray>()
val DEFAULT_REGION_KEYS = intArrayOf(0,0,0,0)
fun get(regionId: Int): IntArray{
return XTEAS[regionId] ?: DEFAULT_REGION_KEYS
}
val parser = JSONParser()
var reader: FileReader? = null
fun load() {
var count = 0
reader = FileReader(xteaJson)
val obj = parser.parse(reader) as JSONObject
val configlist = obj["xteas"] as JSONArray
for(config in configlist){
val e = config as JSONObject
val id = e["regionId"].toString().toInt()
val keys = e["keys"].toString().split(",").map(String::toInt)
XTEAS[id] = intArrayOf(keys[0],keys[1],keys[2],keys[3])
count++
}
}
}

View file

@ -0,0 +1,48 @@
package cacheops.cache.definition.encoder
import Rs2MapEditor
import cacheops.cache.definition.decoder.Item
import const.Indices
import java.nio.ByteBuffer
import javax.swing.JOptionPane
object GroundItemEncoder {
fun write(item: ArrayList<Item>) {
// Setup buffer | Determine capacity (ArrayList size * (short2 + short2 + short2 + int4))
val buffer = ByteBuffer.allocate(item.size * 10)
// Put data to buffer
item.forEach {
val formattedCoord = (it.plane shl 14) or (it.x shl 7) or it.y
buffer.putShort(formattedCoord.toShort())
buffer.putShort(it.id.toShort())
buffer.putShort(it.respawnTime.toShort())
buffer.putInt(it.amount)
}
// Convert buffer to byte array
val dataArray = buffer.array()
// Get region information
val region = Rs2MapEditor.region
val x = (region shr 8) and 0xFF
val y = region and 0xFF
// Put region data
if (dataArray != null) {
Rs2MapEditor.library.put(Indices.LANDSCAPES, "i${x}_${y}", dataArray, intArrayOf(0,0,0,0))
Rs2MapEditor.library.update()
JOptionPane.showMessageDialog(Rs2MapEditor.mapPanel, "Items written to cache [✓]")
Rs2MapEditor.itemsUpdated = false
} else {
System.err.println("Panic! Something went VERY wrong!")
}
}
}
fun main() {
val itemList = arrayListOf<Item>(Item(946, 24, 2,0, 6, 1))
GroundItemEncoder.write(itemList)
}

View file

@ -0,0 +1,49 @@
package cacheops.cache.definition.encoder
import Rs2MapEditor
import cacheops.cache.definition.data.MapDefinition
import cacheops.cache.definition.decoder.MapTileParser
import const.Indices
import java.nio.ByteBuffer
object MapTileEncoder {
fun write(definition: MapDefinition) {
val buffer = ByteBuffer.allocate(80000)
for (plane in 0 until 4) {
for (localX in 0 until 64) {
for (localY in 0 until 64) {
val tile = definition.getTile(localX, localY, plane)
if (tile.underlayId != 0) {
buffer.put(((tile.underlayId + 81) and 0xFF).toByte())
}
if (tile.settings != 0) {
buffer.put(((tile.settings + 49) and 0xFF).toByte())
}
if (tile.attrOpcode != 0) {
buffer.put((tile.attrOpcode and 0xFF).toByte())
buffer.put((tile.overlayId and 0xFF).toByte())
}
if (tile.height == 0) {
buffer.put((0).toByte())
} else {
buffer.put((1).toByte())
buffer.put((tile.height and 0xFF).toByte())
}
}
}
}
val data = buffer.array().copyOf(buffer.position())
val combinedData = data.plus(MapTileParser.atmosphereDataTail)
val x = (Rs2MapEditor.region shr 8) and 0xFF
val y = Rs2MapEditor.region and 0xFF
if (combinedData != null) {
Rs2MapEditor.library.put(Indices.LANDSCAPES, "m${x}_${y}", combinedData)
Rs2MapEditor.library.update()
} else {
System.err.println("Something went VERY wrong!")
}
}
}

View file

@ -0,0 +1,35 @@
package cacheops.cache.definition.encoder
import Rs2MapEditor
import cacheops.cache.definition.decoder.NPC
import const.Indices
import java.nio.ByteBuffer
import javax.swing.JOptionPane
object NPCSpawnEncoder {
fun write(npc: ArrayList<NPC>) {
val buffer = ByteBuffer.allocate(npc.size * 4)
npc.forEach {
val formattedCoord = (it.plane shl 14) or (it.x shl 7) or it.y
buffer.putShort(formattedCoord.toShort())
buffer.putShort(it.id.toShort())
}
val dataArray = buffer.array()
val region = Rs2MapEditor.region
val x = (region shr 8) and 0xFF
val y = region and 0xFF
if (dataArray != null) {
Rs2MapEditor.library.put(Indices.LANDSCAPES, "n${x}_${y}", dataArray, intArrayOf(0,0,0,0))
Rs2MapEditor.library.update()
JOptionPane.showMessageDialog(Rs2MapEditor.mapPanel, "NPCs written to cache [✓]")
Rs2MapEditor.npcsUpdated = false
} else {
System.err.println("Panic! Something went VERY wrong!")
}
}
}

View file

@ -0,0 +1,210 @@
package cacheops.cache.secure
import cacheops.cache.Cache
import cacheops.cache.buffer.read.Reader
import cacheops.cache.buffer.write.BufferWriter
class Huffman(cache: Cache) {
private var masks: IntArray? = null
private val frequencies: ByteArray
private var decryptKeys: IntArray
private val decryptedKeys: IntArray
private var decryptionValues = listOf(0, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1)
/**
* Load huffman tree from cache for compression
*/
init {
val huffman = cache.getFile(10, 1)!!
frequencies = huffman
masks = IntArray(huffman.size)
decryptKeys = IntArray(8)
val freq = IntArray(33)
var key = 0
//For each non-zero frequency
for ((index, size) in huffman.map { it.toInt() }.filter { it != 0 }.toIntArray().withIndex()) {
//Calculate maximum frequency
val maximumFreq = 1 shl 32 - size
//zero or the previous minimum
val currentFreq = freq[size]
//Store the min
masks!![index] = currentFreq
//Set the frequency to the
freq[size] = if (currentFreq and maximumFreq == 0) {//If the min and max are equal ish?
//Starting from the bottom find the smallest frequency indices
for (idx in size - 1 downTo 1) {
val leftFreq = freq[idx]
if (leftFreq != currentFreq) {
break
}
val rightFreq = 1 shl 32 - idx
if (rightFreq and leftFreq != 0) {
//Move up the tree?
freq[idx] = freq[idx - 1]
break
}
//Merge the two smallest trees
freq[idx] = leftFreq + rightFreq
}
//Sum of their frequencies
maximumFreq + currentFreq
} else {
//Move up the tree?
freq[size - 1]
}
for (idx in size + 1..32) {
if (currentFreq == freq[idx]) {
freq[idx] = freq[size]
}
}
var decryptIndex = 0
val value: Long = Int.MAX_VALUE + 1L
for(count in 0 until size) {
if (currentFreq and value.ushr(count).toInt() == 0) {
decryptIndex++
} else {
if (decryptKeys[decryptIndex] == 0) {
decryptKeys[decryptIndex] = key
}
decryptIndex = decryptKeys[decryptIndex]
}
if (decryptKeys.size <= decryptIndex) {
val keys = IntArray(decryptKeys.size * 2)
System.arraycopy(decryptKeys, 0, keys, 0, decryptKeys.size)
decryptKeys = keys
}
}
decryptKeys[decryptIndex] = index xor -0x1
if (key <= decryptIndex) {
key = 1 + decryptIndex
}
}
decryptedKeys = decryptKeys.map { it xor -0x1 }.toIntArray()
}
/**
* Decompresses string of length [characters] using Huffman coding
* @param packet The packet containing the compressed data
* @param characters The number of string characters to decompress
*/
fun decompress(packet: Reader, characters: Int): String {
val textBuffer = ByteArray(packet.readableBytes())
packet.readBytes(textBuffer)
return decompress(textBuffer, characters) ?: ""
}
fun decompress(message: ByteArray, length: Int): String? {
return try {
if(masks == null) {
return null
}
var charsDecoded = 0
var keyIndex = 0
val sb = StringBuilder()
chars@ for (character in message) {
for (value in decryptionValues) {
if (if (value == 0) character >= 0 else character.toInt() and value == 0) {
keyIndex++
} else {
keyIndex = decryptKeys[keyIndex]
}
val char = decryptedKeys[keyIndex]
if (char >= 0) {
sb.append(char.toChar())
if (length <= ++charsDecoded) {
break@chars
}
keyIndex = 0
}
}
}
sb.toString()
} catch (e: Throwable) {
e.printStackTrace()
null
}
}
/**
* Formats, compresses and writes [message] to [builder] using Huffman coding
* @param message The message to encode
* @param builder The packet to write the compressed data too
*/
@ExperimentalStdlibApi
fun compress(message: String, builder: BufferWriter) {
try {
//Format the message
val messageData = formatMessage(message)
//Write message length
builder.writeSmart(messageData.size)
//Write the compressed message
compress(messageData, builder)
} catch (exception: Throwable) {
exception.printStackTrace()
}
}
/**
* Compresses [message] using Huffman coding and writes to [builder]
* @param message The message to compress, split by symbol into a byte array
* @param builder The packet to write the compressed data too
*/
private fun compress(message: ByteArray, builder: BufferWriter) {
try {
if(masks == null) {
return
}
var key = 0
val startPosition = builder.position()
var position = startPosition shl 3
for (char in message) {
val character = char.toInt() and 0xff
val min = masks!![character]
val size = frequencies[character]
var offset = position shr 3
var bitOffset = position and 0x7
key = key and (-bitOffset shr 31)
position += size
val byteSize = (bitOffset + size - 1 shr 3) + offset
bitOffset += 24
key += min.ushr(bitOffset)
builder.setByte(offset, key)
while (offset < byteSize) {
bitOffset -= 8
key = min.ushr(bitOffset)
builder.setByte(++offset, key)
}
}
//Set the packet position to the correct place
builder.position(7 + position shr 3)
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* Replaces unknown symbols with question marks
* @param message The text to format
* @return message split by character
*/
@ExperimentalStdlibApi
private fun formatMessage(message: String): ByteArray {
val array = ByteArray(message.length)
for ((index, c) in message.withIndex()) {
val char = c.code
array[index] = if (char <= 0 || (char in 128..159) || char > 255) {
63.toByte()
} else {
char.toByte()
}
}
return array
}
}

View file

@ -0,0 +1,56 @@
package cacheops.cache.secure
import java.math.BigInteger
import java.nio.ByteBuffer
import java.security.SecureRandom
object RSA {
/**
* Encrypt/decrypts bytes with key and modulus
*/
fun crypt(data: ByteArray, modulus: BigInteger, key: BigInteger): ByteArray {
return BigInteger(data).modPow(key, modulus).toByteArray()
}
/**
* Encrypt/decrypts [ByteBuffer] with key and modulus
*/
fun crypt(data: ByteBuffer, modulus: BigInteger, key: BigInteger): ByteBuffer {
return ByteBuffer.wrap(BigInteger(data.array()).modPow(key, modulus).toByteArray())
}
@JvmStatic
fun main(args: Array<String>) {
generateRsa()
}
/**
* Generates rsa values
*/
private fun generateRsa() {
val bits = 1024
val random = SecureRandom()
var p: BigInteger
var q: BigInteger
var phi: BigInteger
var modulus: BigInteger
var publicKey: BigInteger
var privateKey: BigInteger
do {
p = BigInteger.probablePrime(bits / 2, random)
q = BigInteger.probablePrime(bits / 2, random)
phi = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE))
modulus = p.multiply(q)
publicKey = BigInteger("65537")
privateKey = publicKey.modInverse(phi)
} while (modulus.bitLength() != bits || privateKey.bitLength() != bits || phi.gcd(publicKey) != BigInteger.ONE)
println("modulus: ${modulus.toString(16)}")
println("public key: ${publicKey.toString(16)}")
println("private key: ${privateKey.toString(16)}")
}
}

View file

@ -0,0 +1,77 @@
package cacheops.cache.secure
import java.nio.ByteBuffer
object Xtea {
/**
* The golden ratio.
*/
private const val GOLDEN_RATIO = -0x61c88647
/**
* The number of rounds.
*/
private const val ROUNDS = 32
/**
* Deciphers the specified [ByteBuffer] with the given key.
* @param buffer The buffer.
* @param key The key.
* @throws IllegalArgumentException if the key is not exactly 4 elements
* long.
*/
fun decipher(buffer: ByteArray, key: IntArray, start: Int = 0) {
if (key.size != 4) {
throw IllegalArgumentException()
}
val numQuads = buffer.size / 8
for (i in 0 until numQuads) {
var sum = GOLDEN_RATIO * ROUNDS
var v0 = getInt(buffer, start + i * 8)
var v1 = getInt(buffer, start + i * 8 + 4)
for (j in 0 until ROUNDS) {
v1 -= (v0 shl 4 xor v0.ushr(5)) + v0 xor sum + key[sum.ushr(11) and 3]
sum -= GOLDEN_RATIO
v0 -= (v1 shl 4 xor v1.ushr(5)) + v1 xor sum + key[sum and 3]
}
putInt(buffer, start + i * 8, v0)
putInt(buffer, start + i * 8 + 4, v1)
}
}
/**
* Enciphers the specified [ByteArray] with the given key.
* @param buffer The buffer.
* @param key The key.
* @throws IllegalArgumentException if the key is not exactly 4 elements
* long.
*/
fun encipher(buffer: ByteArray, start: Int, end: Int, key: IntArray) {
if (key.size != 4)
throw IllegalArgumentException()
val numQuads = (end - start) / 8
for (i in 0 until numQuads) {
var sum = 0
var v0 = getInt(buffer, start + i * 8)
var v1 = getInt(buffer, start + i * 8 + 4)
for (j in 0 until ROUNDS) {
v0 += (v1 shl 4 xor v1.ushr(5)) + v1 xor sum + key[sum and 3]
sum += GOLDEN_RATIO
v1 += (v0 shl 4 xor v0.ushr(5)) + v0 xor sum + key[sum.ushr(11) and 3]
}
putInt(buffer, start + i * 8, v0)
putInt(buffer, start + i * 8 + 4, v1)
}
}
private fun getInt(buffer: ByteArray, index: Int) = (buffer[index].toInt() and 0xff shl 24) or (buffer[index + 1].toInt() and 0xff shl 16) or (buffer[index + 2].toInt() and 0xff shl 8) or (buffer[index + 3].toInt() and 0xff)
private fun putInt(buffer: ByteArray, index: Int, value: Int) {
buffer[index] = (value shr 24).toByte()
buffer[index + 1] = (value shr 16).toByte()
buffer[index + 2] = (value shr 8).toByte()
buffer[index + 3] = value.toByte()
}
}

View file

@ -0,0 +1,10 @@
package const
object Archives {
/**
* Archives that are located in the CONFIGURATION index (2)
*/
const val FLOOR_UNDERLAYS = 1
const val FLOOR_OVERLAYS = 4
}

View file

@ -0,0 +1,13 @@
package const
import javax.imageio.ImageIO
import javax.swing.ImageIcon
object Image {
val RED_DOT = ImageIcon(ImageIO.read(javaClass.getResource("/dot_red.png")))
val YELLOW_DOT = ImageIcon(ImageIO.read(javaClass.getResource("/dot_yellow.png")))
val DELETE_HI = ImageIcon(ImageIO.read(javaClass.getResource("/trash_hi.png")))
val DELTE_LO = ImageIcon(ImageIO.read(javaClass.getResource("/trash_dark.png")))
val ADD_HI = ImageIcon(ImageIO.read(javaClass.getResource("/add_hi.png")))
val ADD_LO = ImageIcon(ImageIO.read(javaClass.getResource("/add_dark.png")))
}

View file

@ -0,0 +1,32 @@
package const
object Indices {
const val SKELETONS = 0
const val SKINS = 1
const val CONFIGURATION = 2
const val INTERFACES = 3
const val SYNTH_SOUNDS = 4
const val LANDSCAPES = 5
const val MUSIC = 6
const val MODELS = 7
const val SPRITES = 8
const val TEXTURES = 9
const val HUFFMAN_ENCODING = 10
const val MIDI_JINGLES = 11
const val CLIENT_SCRIPTS = 12
const val FONT_METRICS = 13
const val VORBIS = 14
const val MIDI_INSTRUMENTS = 15
const val CONFIGURATION_OBJECT = 16
const val CONFIGURATION_ENUMS = 17
const val CONFIGURATION_NPCS = 18
const val CONFIGURATION_ITEMS = 19
const val CONFIGURATION_SEQUENCES = 20
const val CONFIGURATION_SPOTANIM = 21
const val CONFIGURATION_VARBIT = 22
const val WORLD_MAP = 23
const val QUICKCHAT_MESSAGES = 24
const val QUICKCHAT_MENUS = 25
const val MATERIALS = 26
const val CONFIGURATION_PARTICLES = 27
}

View file

@ -0,0 +1,8 @@
package const
import cacheops.cache.Cache
import cacheops.cache.CacheDelegate
val cachePath = "/home/ceikry/IdeaProjects/2009scape/Server/data/cache"
val xteaJson = "/home/ceikry/IdeaProjects/2009scape/Server/data/configs/xteas.json"
val cache: Cache = CacheDelegate(cachePath)

View file

@ -0,0 +1,61 @@
package ext
import java.nio.ByteBuffer
fun ByteBuffer.medium(): Int {
return (((get().toInt() shl 16) and 0xff0000) + ((get().toInt() shl 8) and 0xff00) + (get().toInt() and 0xff))
// return ((get().toInt() and 0xff) + (get().toInt() shl 8 and 0xff00) + )
}
fun ByteBuffer.putJagexString(string: String) {
put(0)
put(string.toByteArray())
put(0)
}
fun ByteBuffer.putJagexStringQuickChat(string: String) {
put(1)
put(string.toByteArray())
put(0)
}
fun ByteBuffer.getJagexString(): String {
val stringBuilder = StringBuilder()
var b: Byte
while (get().also { b = it }.toInt() != 0) {
stringBuilder.append(b.toInt().toChar())
}
return stringBuilder.toString()
}
fun ByteBuffer.readNullCircumfixedString(): String {
if (unsignedByte() != 0)
throw IllegalArgumentException("byte != 0 infront of null-circumfixed string")
return getJagexString()
}
fun ByteBuffer.unsignedByte(): Int {
return get().toInt() and 0xFF
}
fun ByteBuffer.unsignedShort(): Int {
return short.toInt() and 0xFFFF
}
fun ByteBuffer.getBigSmart(): Int {
var value = 0
var current: Int = getSmart()
while (current == 32767) {
current = getSmart()
value += 32767
}
value += current
return value
}
fun ByteBuffer.getSmart(): Int {
val peek: Int = get().toInt() and 0xFF
return if (peek <= Byte.MAX_VALUE) {
peek
} else (peek shl 8 or (get().toInt() and 0xFF)) - 32768
}

View file

@ -0,0 +1,12 @@
import cacheops.cache.definition.data.MapTile
import cacheops.cache.definition.decoder.MapTileParser
fun Pair<Int,Int>.getSurroundingTiles() : List<MapTile> {
val list = ArrayList<MapTile>()
list.add(MapTileParser.definition.getTile(first, second + 1, Rs2MapEditor.plane))
list.add(MapTileParser.definition.getTile(first + 1, second, Rs2MapEditor.plane))
list.add(MapTileParser.definition.getTile(first, second - 1, Rs2MapEditor.plane))
list.add(MapTileParser.definition.getTile(first - 1, second, Rs2MapEditor.plane))
return list
}

View file

@ -0,0 +1,24 @@
package ext
class Vector3f(var x: Float, var y: Float, var z: Float) {
override fun hashCode(): Int {
var result = x.hashCode()
result = 31 * result + y.hashCode()
result = 31 * result + z.hashCode()
return result
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Vector3f
if (x != other.x) return false
if (y != other.y) return false
if (z != other.z) return false
return true
}
}

View file

@ -0,0 +1,22 @@
package misc
import java.awt.AWTEvent
import java.awt.Event
import java.awt.EventQueue
import java.awt.Toolkit
import java.awt.event.KeyEvent
class CustomEventQueue : EventQueue() {
override fun dispatchEvent(event: AWTEvent?) {
if(event is KeyEvent){
GlobalKeybinds.handle(event)
}
super.dispatchEvent(event)
}
companion object {
fun install() {
Toolkit.getDefaultToolkit().systemEventQueue.push(CustomEventQueue())
}
}
}

View file

@ -0,0 +1,65 @@
package misc
import cacheops.cache.definition.encoder.GroundItemEncoder
import cacheops.cache.definition.encoder.NPCSpawnEncoder
import java.awt.Event
import java.awt.event.KeyEvent
import tools.*
var ctrlPressed = false
object GlobalKeybinds{
fun handle(event: KeyEvent){
if(event.id == Event.KEY_PRESS){
if(event.keyCode == KeyEvent.VK_CONTROL) {
ctrlPressed = true
}
return
}
if(event.id == Event.KEY_RELEASE){
if(event.keyCode == KeyEvent.VK_CONTROL) {
ctrlPressed = false
return
}
}
if(ctrlPressed){ //Handle keybinds that rely on control being pressed
when(event.keyCode){
KeyEvent.VK_S -> { //CTRL+S
if(Rs2MapEditor.npcsUpdated){
//NPCSpawnEncoder.write(Rs2MapEditor.npcs)
Editors.NPC_SPAWNS.data.save()
}
if(Rs2MapEditor.itemsUpdated){
GroundItemEncoder.write(Rs2MapEditor.items)
}
}
KeyEvent.VK_UP -> {
var newRegion = Util.getRegion (Rs2MapEditor.region, 0, 1)
Rs2MapEditor.loadRegion(newRegion)
}
KeyEvent.VK_DOWN -> {
var newRegion = Util.getRegion (Rs2MapEditor.region, 0, -1)
Rs2MapEditor.loadRegion(newRegion)
}
KeyEvent.VK_LEFT -> {
var newRegion = Util.getRegion (Rs2MapEditor.region, -1, 0)
Rs2MapEditor.loadRegion(newRegion)
}
KeyEvent.VK_RIGHT -> {
var newRegion = Util.getRegion (Rs2MapEditor.region, 1, 0)
Rs2MapEditor.loadRegion(newRegion)
}
}
}
else when(event.keyCode){
KeyEvent.VK_ESCAPE -> Rs2MapEditor.state = EditorState.NONE
}
}
}

View file

@ -0,0 +1,56 @@
package misc
import java.awt.Image
import java.awt.event.MouseEvent
import java.awt.event.MouseListener
import javax.swing.ImageIcon
import javax.swing.JLabel
open class ImgButton(enabledImg: ImageIcon, disabledImage: ImageIcon = enabledImg, val autoHandleMouse: Boolean = true) : JLabel() {
private var hoverMethod: (MouseEvent) -> Unit = {}
private var mouseLeaveMethod: (MouseEvent) -> Unit = {}
private var onClickMethod: (MouseEvent) -> Unit = {}
init {
isEnabled = false
icon = enabledImg
disabledIcon = disabledImage
addMouseListener(object : MouseListener {
override fun mouseClicked(p0: MouseEvent) {
onClickMethod.invoke(p0)
}
override fun mousePressed(p0: MouseEvent?) {}
override fun mouseReleased(p0: MouseEvent?) {}
override fun mouseEntered(p0: MouseEvent) {
if(autoHandleMouse) isEnabled = true
hoverMethod.invoke(p0)
}
override fun mouseExited(p0: MouseEvent) {
if(autoHandleMouse) isEnabled = false
mouseLeaveMethod.invoke(p0)
}
})
}
fun onClick(handler: (event: MouseEvent) -> Unit){
onClickMethod = handler
}
fun onMouseEnter(handler: (event: MouseEvent) -> Unit){
hoverMethod = handler
}
fun onMouseExit(handler: (event: MouseEvent) -> Unit){
mouseLeaveMethod = handler
}
fun scale(width: Int, height: Int){
icon = ImageIcon((icon as ImageIcon).image.getScaledInstance(width,height, Image.SCALE_SMOOTH))
disabledIcon = ImageIcon((disabledIcon as ImageIcon).image.getScaledInstance(width, height, Image.SCALE_SMOOTH))
}
}

View file

@ -0,0 +1,101 @@
package tools
import cacheops.cache.definition.decoder.decoder
import cacheops.cache.definition.decoder.itemDecoder
import java.awt.BorderLayout
import java.awt.Dimension
import java.awt.event.KeyEvent
import java.awt.event.KeyListener
import java.awt.event.MouseEvent
import java.awt.event.MouseListener
import java.util.*
import java.util.regex.PatternSyntaxException
import javax.swing.*
import javax.swing.table.DefaultTableCellRenderer
import javax.swing.table.DefaultTableModel
import javax.swing.table.TableRowSorter
object ItemSearchTool : JFrame("Item Search") {
var model = DefaultTableModel()
var searchField = JTextField()
var sorter = TableRowSorter(model)
var cellRenderer = DefaultTableCellRenderer()
var populated = false
var caller: ((Int,String) -> Unit)? = null
private fun filter() {
var rf: RowFilter<DefaultTableModel?, Any?>? = null
//If current expression doesn't parse, don't update.
rf = try {
RowFilter.regexFilter(searchField.text.capitalize(), 1)
} catch (e: PatternSyntaxException) {
return
}
sorter.rowFilter = rf
}
fun open() {
if (!populated) {
SwingUtilities.invokeLater {
for (i in 0..15431) {
model.addRow(arrayOf(i, itemDecoder.forId(i).name))
}
isVisible = true
populated = true
}
} else {
isVisible = true
}
}
init {
layout = BorderLayout()
cellRenderer.toolTipText = "Double-Click to select."
val searchPanel = JPanel()
val searchLabel = JLabel("Search for NPC:")
searchField.preferredSize = Dimension(100, 20)
searchPanel.add(searchLabel)
searchPanel.add(searchField)
add(searchPanel, BorderLayout.NORTH)
setLocationRelativeTo(null)
val itemTable: JTable = object : JTable(model) {
override fun editCellAt(i: Int, i1: Int, eventObject: EventObject): Boolean {
return false
}
}
model.addColumn("ID")
model.addColumn("Name")
itemTable.rowSorter = sorter
itemTable.columnModel.getColumn(0).maxWidth = 55
itemTable.columnModel.getColumn(0).cellRenderer = cellRenderer
itemTable.columnModel.getColumn(1).cellRenderer = cellRenderer
itemTable.addMouseListener(object : MouseListener {
override fun mouseClicked(mouseEvent: MouseEvent) {
if (mouseEvent.clickCount == 2) {
val table = mouseEvent.source as JTable
val row = table.selectedRow
val selectedID = table.getValueAt(row,0).toString().toInt()
val selectedName = table.getValueAt(row,1).toString()
caller?.invoke(selectedID,selectedName)
isVisible = false
}
}
override fun mousePressed(mouseEvent: MouseEvent) {}
override fun mouseReleased(mouseEvent: MouseEvent) {}
override fun mouseEntered(mouseEvent: MouseEvent) {}
override fun mouseExited(mouseEvent: MouseEvent) {}
})
searchField.addKeyListener(object : KeyListener {
override fun keyTyped(keyEvent: KeyEvent) {
filter()
}
override fun keyPressed(keyEvent: KeyEvent) {}
override fun keyReleased(keyEvent: KeyEvent) {}
})
val scrollPane = JScrollPane(itemTable)
add(scrollPane, BorderLayout.SOUTH)
pack()
isVisible = false
}
}

View file

@ -0,0 +1,100 @@
package tools
import cacheops.cache.definition.decoder.decoder
import java.awt.BorderLayout
import java.awt.Dimension
import java.awt.event.KeyEvent
import java.awt.event.KeyListener
import java.awt.event.MouseEvent
import java.awt.event.MouseListener
import java.util.*
import java.util.regex.PatternSyntaxException
import javax.swing.*
import javax.swing.table.DefaultTableCellRenderer
import javax.swing.table.DefaultTableModel
import javax.swing.table.TableRowSorter
object NPCSearchTool : JFrame("NPC Search") {
var model = DefaultTableModel()
var searchField = JTextField()
var sorter = TableRowSorter(model)
var cellRenderer = DefaultTableCellRenderer()
var populated = false
var caller: ((Int,String) -> Unit)? = null
private fun filter() {
var rf: RowFilter<DefaultTableModel?, Any?>? = null
//If current expression doesn't parse, don't update.
rf = try {
RowFilter.regexFilter(searchField.text.capitalize(), 1)
} catch (e: PatternSyntaxException) {
return
}
sorter.rowFilter = rf
}
fun open() {
if (!populated) {
SwingUtilities.invokeLater {
for (i in 0..9422) {
model.addRow(arrayOf(i, decoder.forId(i).name))
}
isVisible = true
populated = true
}
} else {
isVisible = true
}
}
init {
layout = BorderLayout()
cellRenderer.toolTipText = "Double-Click to select."
val searchPanel = JPanel()
val searchLabel = JLabel("Search for NPC:")
searchField.preferredSize = Dimension(100, 20)
searchPanel.add(searchLabel)
searchPanel.add(searchField)
add(searchPanel, BorderLayout.NORTH)
setLocationRelativeTo(null)
val npcTable: JTable = object : JTable(model) {
override fun editCellAt(i: Int, i1: Int, eventObject: EventObject): Boolean {
return false
}
}
model.addColumn("ID")
model.addColumn("Name")
npcTable.rowSorter = sorter
npcTable.columnModel.getColumn(0).maxWidth = 55
npcTable.columnModel.getColumn(0).cellRenderer = cellRenderer
npcTable.columnModel.getColumn(1).cellRenderer = cellRenderer
npcTable.addMouseListener(object : MouseListener {
override fun mouseClicked(mouseEvent: MouseEvent) {
if (mouseEvent.clickCount == 2) {
val table = mouseEvent.source as JTable
val row = table.selectedRow
val selectedID = table.getValueAt(row,0).toString().toInt()
val selectedName = table.getValueAt(row,1).toString()
caller?.invoke(selectedID,selectedName)
isVisible = false
}
}
override fun mousePressed(mouseEvent: MouseEvent) {}
override fun mouseReleased(mouseEvent: MouseEvent) {}
override fun mouseEntered(mouseEvent: MouseEvent) {}
override fun mouseExited(mouseEvent: MouseEvent) {}
})
searchField.addKeyListener(object : KeyListener {
override fun keyTyped(keyEvent: KeyEvent) {
filter()
}
override fun keyPressed(keyEvent: KeyEvent) {}
override fun keyReleased(keyEvent: KeyEvent) {}
})
val scrollPane = JScrollPane(npcTable)
add(scrollPane, BorderLayout.SOUTH)
pack()
isVisible = false
}
}

View file

@ -0,0 +1,23 @@
package tools
object Util {
fun getRegionId(location: TableData.Location) : Int {
return ((location.x shr 6) shl 8) or (location.y shr 6)
}
fun getRegionCoordinates(location: TableData.Location) : IntArray {
return intArrayOf(location.x and 63, location.y and 63, location.z)
}
fun getAbsoluteCoordinates(regionId: Int, regionX: Int, regionY: Int, plane: Int) : TableData.Location {
val x = regionId shr 8
val y = regionId and 0xFF
return TableData.Location((x shl 6) or regionX, (y shl 6) or regionY, plane)
}
fun getRegion (currentRegionId: Int, changeX: Int, changeY: Int) : Int {
var x = ((currentRegionId shr 8) + changeX) shl 8
var y = ((currentRegionId and 0xFF) + changeY)
return (x or y)
}
}

View file

@ -0,0 +1,23 @@
package ui
import java.awt.Color
import java.awt.Dimension
import java.awt.event.KeyEvent
import javax.swing.JComponent
import javax.swing.JTabbedPane
import javax.swing.border.CompoundBorder
import javax.swing.border.EmptyBorder
import javax.swing.border.LineBorder
class InfoPane : JTabbedPane() {
init {
val informationComponent: JComponent = TileInformationPanel()
preferredSize = Dimension(230, 4000)
border = CompoundBorder(LineBorder(Color.DARK_GRAY), EmptyBorder(0, 0, 0, 0))
addTab("Information", informationComponent)
add("NPC Spawn", Rs2MapEditor.npcPanel)
add("Item Spawn", Rs2MapEditor.itemPanel)
}
}

View file

@ -0,0 +1,128 @@
package ui
import cacheops.cache.definition.decoder.Item
import const.Image
import misc.ImgButton
import java.awt.BorderLayout
import java.awt.Color
import java.awt.Dimension
import java.awt.FlowLayout
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import javax.swing.BoxLayout
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.border.MatteBorder
class ItemSpawnPanel : JPanel() {
val rowBorder = MatteBorder(1, 1, 1, 1, Color.WHITE)
init {
layout = BoxLayout(this, BoxLayout.PAGE_AXIS)
add(ItemSpawnerPanel())
Rs2MapEditor.items.forEach {
val row = ItemRow(it, this)
row.border = rowBorder
Rs2MapEditor.itemRows.add(row)
add(row)
}
}
fun redrawRows() {
Rs2MapEditor.itemRows.forEach {
remove(it)
}
Rs2MapEditor.itemRows.clear()
Rs2MapEditor.items.filter { it.plane == Rs2MapEditor.plane }.forEach {
val row = ItemRow(it, this)
row.border = rowBorder
Rs2MapEditor.itemRows.add(row)
add(row)
}
repaint()
}
class ItemSpawnerPanel : JPanel() {
init {
val topPanel = JPanel(FlowLayout())
val bottomPanel = JPanel(FlowLayout())
val addButton = ImgButton(Image.ADD_HI, Image.ADD_LO)
addButton.onClick {
Rs2MapEditor.state = EditorState.ADD_GROUNDITEM
}
Rs2MapEditor.itemIdInput.minimumSize = Dimension(200, 25)
Rs2MapEditor.itemIdInput.maximumSize = Dimension(200, 25)
Rs2MapEditor.itemIdInput.preferredSize = Dimension(200, 25)
Rs2MapEditor.itemRespawnInput.minimumSize = Dimension(50, 25)
Rs2MapEditor.itemRespawnInput.maximumSize = Dimension(50, 25)
Rs2MapEditor.itemRespawnInput.preferredSize = Dimension(50, 25)
Rs2MapEditor.itemRespawnInput.text = "1"
Rs2MapEditor.itemAmountInput.minimumSize = Dimension(75, 25)
Rs2MapEditor.itemAmountInput.maximumSize = Dimension(75, 25)
Rs2MapEditor.itemAmountInput.preferredSize = Dimension(75, 25)
Rs2MapEditor.itemAmountInput.text = "1"
val timeLabel = JLabel("\uD83D\uDD64")
timeLabel.toolTipText = "Respawn Time (ticks)"
minimumSize = Dimension(300, 68)
preferredSize = Dimension(300, 68)
maximumSize = Dimension(300, 68)
layout = BorderLayout()
topPanel.add(Rs2MapEditor.itemIdInput)
topPanel.add(addButton)
bottomPanel.add(timeLabel)
bottomPanel.add(Rs2MapEditor.itemRespawnInput)
bottomPanel.add(JLabel("AMT:"))
bottomPanel.add(Rs2MapEditor.itemAmountInput)
add(topPanel,BorderLayout.NORTH)
add(bottomPanel,BorderLayout.SOUTH)
border = MatteBorder(1, 1, 1, 1, Color.GREEN)
}
}
class ItemRow(val item: Item, val parent: JPanel) : JPanel(){
init {
layout = FlowLayout()
add(JLabel("${item.definition.name} [${item.amount}] -- \uD83D\uDD64 ${item.respawnTime}"))
val deleteButton = ImgButton(Image.DELETE_HI, Image.DELTE_LO)
add(deleteButton)
minimumSize = Dimension(300, 40)
preferredSize = Dimension(300, 40)
maximumSize = Dimension(300, 40)
deleteButton.onClick {
Rs2MapEditor.items.remove(item)
parent.remove(this)
parent.repaint()
Rs2MapEditor.itemRows.remove(this)
if(Rs2MapEditor.items.filter { it.x == item.x && it.y == item.y }.isEmpty()){
Rs2MapEditor.componentPointMap.filter { it.key.x == item.x && it.key.y == item.y }.forEach { (_,cell) ->
cell.components.forEach { c ->
if(c is JLabel && c.icon == Image.RED_DOT) cell.remove(c)
}
cell.repaint()
Rs2MapEditor.itemsUpdated = true
}
}
}
addMouseListener(object : MouseAdapter(){
val border = MatteBorder(1, 1, 1, 1, Color.YELLOW)
val defaultBorder = MatteBorder(1, 1, 1, 1, Color.GRAY)
override fun mouseEntered(e: MouseEvent?) {
super.mouseEntered(e)
Rs2MapEditor.componentPointMap.filter { it.key.x == item.x && it.key.y == item.y }.forEach { it.value.border = border }
}
override fun mouseExited(e: MouseEvent?) {
super.mouseExited(e)
Rs2MapEditor.componentPointMap.filter { it.key.x == item.x && it.key.y == item.y }.forEach{ it.value.border = defaultBorder }
}
})
}
}
}

View file

@ -0,0 +1,396 @@
package ui
import EditorData
import EditorState
import Rs2MapEditor
import TableData
import cacheops.cache.definition.data.MapTile
import cacheops.cache.definition.decoder.Item
import cacheops.cache.definition.decoder.MapTileParser
import cacheops.cache.definition.decoder.NPC
import cacheops.cache.definition.decoder.Scenery
import const.Image
import tools.Util
import java.awt.*
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.SwingUtilities
class MapCell : JPanel() {
var defaultBackground: Color = background
val scenery = ArrayList<Scenery>()
override fun getPreferredSize(): Dimension {
return Dimension(Rs2MapEditor.cellX, Rs2MapEditor.cellY)
}
init {
//add(underlayLabel)
addMouseListener(object : MouseAdapter() {
override fun mouseEntered(e: MouseEvent) {
Rs2MapEditor.selectedPointX = e.component.bounds.location.x / Rs2MapEditor.cellX
Rs2MapEditor.selectedPointY = e.component.bounds.location.y / Rs2MapEditor.cellY
Rs2MapEditor.statusLabel.foreground = Color.YELLOW
Rs2MapEditor.statusLabel.text = "<html>Region: ${Rs2MapEditor.region} | " +
"Local Coordinates: [${Rs2MapEditor.selectedPointX}, ${Rs2MapEditor.selectedPointY}] | " +
"Global Coordinates: [${MapTileParser.coordinateX(Rs2MapEditor.selectedPointX)}, ${
MapTileParser.coordinateX(
Rs2MapEditor.selectedPointY
)
}] | " +
"Viewing Underlay: ${
MapTileParser.definition.getTile(
Rs2MapEditor.selectedPointX,
Rs2MapEditor.selectedPointY, 0).underlayId} | " +
"Selected Underlay: ${if (Rs2MapEditor.selectedUnderlayId == null) "<font color='red'>No underlay selected!</font>" else "${Rs2MapEditor.selectedUnderlayId}"}</html>"
defaultBackground = background
if(Rs2MapEditor.state == EditorState.SET_UNDERLAY || Rs2MapEditor.state == EditorState.NONE) {
background = Color.BLUE
} else if (Rs2MapEditor.state == EditorState.ADD_NPC){
background = Color.YELLOW
} else if (Rs2MapEditor.state == EditorState.ADD_GROUNDITEM){
background = Color.RED
}
}
override fun mouseExited(e: MouseEvent) {
background = defaultBackground
}
override fun mouseClicked(e: MouseEvent) {
if (SwingUtilities.isLeftMouseButton(e)) {
if (Rs2MapEditor.selectedUnderlayId != null && Rs2MapEditor.state == EditorState.SET_UNDERLAY) {
val originalTile = MapTileParser.definition.getTile(
Rs2MapEditor.selectedPointX,
Rs2MapEditor.selectedPointY, 0)
val underlayID = Rs2MapEditor.selectedUnderlayId
val point = Point(Rs2MapEditor.selectedPointX, Rs2MapEditor.selectedPointY)
val oldValue = Rs2MapEditor.colorPointMap[point]
Rs2MapEditor.colorPointMap[point] = underlayID!!
println("UPDATED UNDERLAY VALUES @ [${point.x}, ${point.y}] [$oldValue >> ${Rs2MapEditor.colorPointMap[point]}]")
defaultBackground = Rs2MapEditor.underlayMap[Rs2MapEditor.selectedUnderlayId]?.getRGB()!!
background = Rs2MapEditor.underlayMap[Rs2MapEditor.selectedUnderlayId]?.getRGB()
// Update map tile cacheops.definitions with new tile information
MapTileParser.definition.setTile(point.x, point.y, Rs2MapEditor.plane,
MapTile(
originalTile.height,
originalTile.attrOpcode,
originalTile.overlayId,
originalTile.overlayPath,
originalTile.overlayRotation,
originalTile.settings,
underlayID
)
)
}
else if (Rs2MapEditor.npcIdInput.text.isNotEmpty() && Rs2MapEditor.state == EditorState.ADD_NPC){
val id = Rs2MapEditor.npcIdInput.text.toIntOrNull()
if(id == null){
Rs2MapEditor.state = EditorState.NONE
return
}
val canWalk = Rs2MapEditor.npcCanWalkCheckbox.isSelected()
var spawnDirection = 0
for ((index, checkbox) in Rs2MapEditor.npcDirectionCheckboxes.withIndex()) {
if (checkbox.isSelected()) { spawnDirection = index; break }
}
val absolute = Util.getAbsoluteCoordinates(Rs2MapEditor.region, Rs2MapEditor.selectedPointX, Rs2MapEditor.selectedPointY, Rs2MapEditor.plane)
val npcSpawn = TableData.NPCSpawn(id, absolute, canWalk, spawnDirection)
Rs2MapEditor.npcs!!.add(npcSpawn)
Rs2MapEditor.componentPointMap.filter { it.key.x == Rs2MapEditor.selectedPointX && it.key.y == Rs2MapEditor.selectedPointY }.forEach { (_, cell) ->
var hasLabel = false
cell.components.forEach { if(it is JLabel && it.icon == Image.YELLOW_DOT) hasLabel = true }
cell.layout = FlowLayout()
if(!hasLabel) cell.add(JLabel(Image.YELLOW_DOT))
cell.repaint()
}
Rs2MapEditor.npcPanel.redrawRows()
Rs2MapEditor.npcsUpdated = true
}
else if (Rs2MapEditor.itemIdInput.text.isNotEmpty() && Rs2MapEditor.state == EditorState.ADD_GROUNDITEM){
val id = Rs2MapEditor.itemIdInput.text.toIntOrNull()
val amount = Rs2MapEditor.itemAmountInput.text.toIntOrNull() ?: 1
val respawnTime = Rs2MapEditor.itemRespawnInput.text.toIntOrNull() ?: 1
if(id == null){
Rs2MapEditor.state = EditorState.NONE
return
}
val item = Item(
id,
Rs2MapEditor.selectedPointX,
Rs2MapEditor.selectedPointY,
Rs2MapEditor.plane,
respawnTime,
amount
)
Rs2MapEditor.items.add(item)
Rs2MapEditor.componentPointMap.filter { it.key.x == Rs2MapEditor.selectedPointX && it.key.y == Rs2MapEditor.selectedPointY }.forEach { (_, cell) ->
var hasLabel = false
cell.components.forEach { if(it is JLabel && it.icon == Image.RED_DOT) hasLabel = true }
cell.layout = FlowLayout()
if(!hasLabel) cell.add(JLabel(Image.RED_DOT))
cell.repaint()
}
Rs2MapEditor.itemPanel.redrawRows()
Rs2MapEditor.itemsUpdated = true
}
} else if (SwingUtilities.isRightMouseButton(e)) {
val point = Point(Rs2MapEditor.selectedPointX, Rs2MapEditor.selectedPointY)
val def = MapTileParser.definition.getTile(point.x, point.y, Rs2MapEditor.plane)
val floDef = Rs2MapEditor.overlayMap[def.overlayId]!!
val cell = Rs2MapEditor.componentPointMap[point]!!
val string = StringBuilder()
.append("<h2><b>Tile [${point.x}, ${point.y}] Information</b></h2><br>")
.append("<hr width=\"250px\"><br>")
.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>UnderlayID</th>")
.append("<th>Height</th>")
.append("<th>Settings</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
.append("<tr style=\"text-align:center\">")
.append("<td>${def.underlayId}</td>")
.append("<td>${def.height}</td>")
.append("<td>${def.settings}</td>")
.append("</tr>")
.append("</tbody>")
.append("</table>")
.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>OverlayID</th>")
.append("<th>Color</th>")
.append("<th>Hide underlay</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
.append("<tr style=\"text-align:center\">")
.append("<td>${def.overlayId}</td>")
.append("<td>${floDef.color}</td>")
.append("<td>${floDef.hideUnderlay}</td>")
.append("</tr>")
.append("</tbody>")
.append("</table>")
.append("<br/>")
val thisAbsolute = Util.getAbsoluteCoordinates(Rs2MapEditor.region, Rs2MapEditor.selectedPointX, Rs2MapEditor.selectedPointY, Rs2MapEditor.plane)
val itemsHere = Rs2MapEditor.items.filter { it.x == Rs2MapEditor.selectedPointX && it.y == Rs2MapEditor.selectedPointY && it.plane == Rs2MapEditor.plane }.toList()
val npcsHere = Rs2MapEditor.npcs!!.filter { it.location == thisAbsolute }.toList()
if(npcsHere.isNotEmpty()) {
string.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>NPC ID</th>")
.append("<th>Name</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
for (npc in npcsHere) {
string.append("<tr style=\"text-align:center\">")
string.append("<td>${npc.id}</td>")
string.append("<td>${TableData.npcNames[npc.id]}</td>")
string.append("</tr>")
}
string.append("</tbody></table><br/>")
}
if(itemsHere.isNotEmpty()) {
string.append("<table style=\"border:1px solid gray;margin-left:auto;margin-right:auto;>")
.append("<thead>")
.append("<tr style=\"text-align:center\">")
.append("<th>Item ID</th>")
.append("<th>Info</th>")
.append("</tr>")
.append("</thead>")
.append("<tbody>")
for (item in itemsHere) {
string.append("<tr style=\"text-align:center\">")
string.append("<td>${item.id}</td>")
string.append("<td>${item.definition.name}[${item.amount}] \uD83D\uDD64${item.respawnTime}</td>")
string.append("</tr>")
}
string.append("</tbody></table><br/>")
}
if(scenery.isNotEmpty()) {
string.append("<h3>Scenery Info</h3>")
for(sc in scenery) {
if (sc.id != -1) {
string.append("${sc.definition.name} [ID: ${sc.id}]<br/>")
string.append("Type: ${sc.type}<br/>")
string.append("Rotation: ${sc.rotation}<br/>")
string.append("---------------------<br/>")
}
}
}
Rs2MapEditor.underlayInfo.text = String.format("<html><body style=\"text-align: center;\">%s</body></html>", string.toString())
Rs2MapEditor.infoPane.selectedIndex = 0
}
}
})
}
fun flagScenery(scenery: Scenery){
this.scenery.add(scenery)
}
override fun paintComponent(g: Graphics) {
if(this.defaultBackground == Color(0,0,0,0)) return
super.paintComponent(g)
for(sc in scenery) {
var pointX1 = 0
var pointY1 = 0
var pointX2 = 0
var pointY2 = 0
val color = g.color
val rotationOdd = sc.rotation % 2 != 0
when (sc.type) {
10 -> g.drawOval(5, 5, this.width - 10, this.height - 10)
4 -> {
val offSetX =
if (!rotationOdd) (sc.rotation * 0.375 * width).toInt() else (0.35 * width).toInt()
val offSetY =
if (!rotationOdd) (0.65 * height).toInt() else (sc.rotation * 0.375 * height).toInt()
g.drawString("=", offSetX, offSetY)
}
11 -> {
g.color = Color(255, 255, 255, 75)
g.drawString("", (0.25 * width).toInt(), (0.75 * height).toInt())
g.color = color
}
22 -> {
g.color = Color(255, 255, 255, 55)
g.drawString("", (0.15 * width).toInt(), (0.65 * height).toInt())
g.color = color
}
0, 5 -> {
if (sc.id == 85) return
when (sc.rotation) {
0 -> {
pointX1 = 1; pointY1 = this.height - 1; pointX2 = 1; pointY2 = 1
}
1 -> {
pointX1 = 1; pointY1 = 1; pointX2 = this.width - 1; pointY2 = 1
}
2 -> {
pointX1 = this.width - 1; pointY1 = 1; pointX2 = this.width - 1; pointY2 = this.height - 1
}
3 -> {
pointX1 = 1; pointY1 = this.height - 1; pointX2 = this.width - 1; pointY2 = this.height - 1
}
}
if (sc.definition.interactive == 1 && sc.type == 0) {
g.color = Color.RED
}
g.drawLine(pointX1, pointY1, pointX2, pointY2)
g.color = color
}
2 -> {
val nPoints = 4
var xArray: IntArray = intArrayOf(0, 0, 0, 0)
var yArray: IntArray = intArrayOf(0, 0, 0, 0)
when (sc.rotation) {
0 -> {
xArray = intArrayOf(1, 1, 1, this.width - 1); yArray = intArrayOf(1, this.height - 1, 1, 1)
}
1 -> {
xArray = intArrayOf(1, this.width - 1, this.width - 1, this.width - 1); yArray = intArrayOf(1, 1, 1, this.height - 1)
}
2 -> {
xArray = intArrayOf(1, this.width - 1, this.width - 1, this.width - 1); yArray = intArrayOf(this.height - 1, this.height - 1, 1, this.height - 1)
}
3 -> {
xArray = intArrayOf(1,1,1,this.width - 1); yArray = intArrayOf(1,this.height - 1, this.height - 1, this.height - 1)
}
}
if (sc.definition.interactive == 1) {
g.color = Color.RED
}
g.drawPolyline(xArray, yArray, nPoints)
g.color = color
}
9, 7, 6, 8 -> {
if (sc.id == 85 || sc.id == 83) return
when (sc.rotation) {
0, 2 -> {
pointX1 = 0; pointY1 = height; pointX2 = width; pointY2 = 0
}
1, 3 -> {
pointX1 = 0; pointY1 = 0; pointX2 = width; pointY2 = height
}
}
val overlayNorth = getOverlayId(sc.x + 1, sc.y)
val overlaySouth = getOverlayId(sc.x - 1, sc.y)
val northWest = getOverlayId(sc.x - 1, sc.y + 1)
val north = getOverlayId(sc.x, sc.y + 1)
val northEast = getOverlayId(sc.x + 1, sc.y + 1)
val east = getOverlayId(sc.x + 1, sc.y)
val southWest = getOverlayId(sc.x - 1, sc.y - 1)
val south = getOverlayId(sc.x, sc.y - 1)
val southEast = getOverlayId(sc.x + 1, sc.y - 1)
val west = getOverlayId(sc.x - 1, sc.y)
var backFillVertice = Pair(0, 0)
when (sc.rotation) {
0, 2 -> {
val sumA = getOverlaySum(north, northWest, west)
val sumB = getOverlaySum(south, southEast, east)
backFillVertice = if (sumA > sumB) Pair(width, height)
else if (sumA == sumB) Pair(-1, -1)
else Pair(0, 0)
}
1, 3 -> {
val sumA = getOverlaySum(north, northEast, east)
val sumB = getOverlaySum(south, southWest, west)
backFillVertice = if (sumA > sumB) Pair(0, height)
else if (sumA == sumB) Pair(-1, -1)
else Pair(width, 0)
}
}
val fluDef = getUnderlayColor(sc.x, sc.y)
g.color = fluDef
if (overlaySouth != overlayNorth && backFillVertice.first != -1)
g.fillPolygon(
intArrayOf(pointX1, pointX2, backFillVertice.first),
intArrayOf(pointY1, pointY2, backFillVertice.second),
3
)
g.color = color
g.drawLine(pointX1, pointY1, pointX2, pointY2)
}
}
}
}
fun getOverlaySum(vararg overlays: Int): Int{
var sum = 0
for(overlay in overlays){
sum += overlay.coerceAtMost(1)
}
return sum
}
fun getUnderlayColor(x: Int, y: Int): Color {
var underlayID = (MapTileParser.definition.getTile(x, y, Rs2MapEditor.plane).underlayId - 1)
if (underlayID < 0) {
underlayID = 0
}
return Rs2MapEditor.underlayMap[underlayID]?.getRGB() ?: Color.BLACK
}
fun getOverlayId(x: Int, y: Int): Int {
return MapTileParser.definition.getTile(x, y, Rs2MapEditor.plane).overlayId
}
}

View file

@ -0,0 +1,215 @@
package ui
import EditorState
import Rs2MapEditor
import TableData
import cacheops.cache.definition.decoder.NPC
import const.Image
import misc.ImgButton
import tools.Util
import java.awt.Color
import java.awt.Dimension
import java.awt.FlowLayout
import java.awt.BorderLayout
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import javax.swing.BoxLayout
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.JTextField
import javax.swing.SwingUtilities
import javax.swing.Box
import javax.swing.SwingConstants
import javax.swing.border.MatteBorder
import javax.swing.event.DocumentListener
import javax.swing.event.DocumentEvent
class NPCSpawnPanel : JPanel() {
val rowBorder = MatteBorder(1, 1, 1, 1, Color.WHITE)
val removedRows = ArrayList<NPCRow>()
init {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
add(NPCSpawnerPanel())
val filterPanel = JPanel(FlowLayout())
val filterLabel = JLabel("Filter ")
val filterBox = JTextField("Enter search term...")
filterBox.document.addDocumentListener(FilterBoxListener(filterBox, ::filterRows))
filterPanel.add(filterLabel)
filterPanel.add(filterBox)
filterBox.minimumSize = Dimension(150, 30)
filterBox.preferredSize = Dimension(150, 30)
filterBox.maximumSize = Dimension(150, 60)
filterPanel.minimumSize = Dimension(300, 60)
filterPanel.maximumSize = Dimension(300, 60)
add(filterPanel)
Rs2MapEditor.npcs!!.forEach {
val row = NPCRow(it, this)
row.border = rowBorder
Rs2MapEditor.npcRows.add(row)
add(row)
}
}
fun filterRows (term: String) {
SwingUtilities.invokeLater {
var termAsInt = term.toIntOrNull()
Rs2MapEditor.npcRows.addAll(removedRows)
var rows = Rs2MapEditor.npcRows.toTypedArray()
removedRows.clear()
if (term.isNotEmpty() && termAsInt != null) {
for (row in rows) {
if (row.npc.id != termAsInt) {
removedRows.add(row)
Rs2MapEditor.npcRows.remove(row)
}
}
}
else if (term.isNotEmpty()) {
for (row in rows) {
var name = TableData.npcNames[row.npc.id]?.toLowerCase() ?: "null"
if (!name.contains(term, ignoreCase = true) && !term.contains(name, ignoreCase = true) && term.toLowerCase() != name) {
removedRows.add(row)
Rs2MapEditor.npcRows.remove(row)
}
}
}
for (row in rows) {
remove(row)
revalidate()
}
for (row in Rs2MapEditor.npcRows) {
add(row)
revalidate()
}
Rs2MapEditor.infoPane.revalidate()
repaint(5L)
Rs2MapEditor.infoScrollPane.scrollFrame.viewport.repaint(5L)
}
}
fun redrawRows() {
Rs2MapEditor.npcRows.forEach {
remove(it)
}
Rs2MapEditor.npcRows.clear()
Rs2MapEditor.npcs!!.filter { it.location.z == Rs2MapEditor.plane }.forEach {
val row = NPCRow(it, this)
row.border = rowBorder
Rs2MapEditor.npcRows.add(row)
add(row)
}
removedRows.clear()
repaint()
}
class NPCSpawnerPanel : JPanel() {
init {
val addButton = ImgButton(Image.ADD_HI, Image.ADD_LO)
addButton.onClick {
Rs2MapEditor.state = EditorState.ADD_NPC
}
Rs2MapEditor.npcIdInput.minimumSize = Dimension(200, 25)
Rs2MapEditor.npcIdInput.maximumSize = Dimension(200, 25)
Rs2MapEditor.npcIdInput.preferredSize = Dimension(200, 25)
Rs2MapEditor.npcIdInput.addMouseListener (object : MouseAdapter() {
override fun mouseClicked (e: MouseEvent) {
NPCMenu.caller = {id, name ->
Rs2MapEditor.npcIdInput.text = id.toString()
}
NPCMenu.open()
}
})
minimumSize = Dimension(300, 120)
preferredSize = Dimension(300, 120)
maximumSize = Dimension(300, 120)
layout = FlowLayout()
add(Rs2MapEditor.npcIdInput)
add(addButton)
add(Rs2MapEditor.directionalCheckboxPanel)
add(JLabel("Can Walk?"))
add(Rs2MapEditor.npcCanWalkCheckbox)
border = MatteBorder(1, 1, 1, 1, Color.GREEN)
}
}
class FilterBoxListener (val textField: JTextField, val filterRows: (String) -> Unit) : DocumentListener {
override fun changedUpdate (e: DocumentEvent) {
filterRows(textField.text)
}
override fun insertUpdate (e: DocumentEvent) {
filterRows(textField.text)
}
override fun removeUpdate (e: DocumentEvent) {
filterRows(textField.text)
}
}
class NPCRow(val npc: TableData.NPCSpawn, val parent: JPanel) : JPanel(){
init {
layout = BorderLayout()
val topPanel = JPanel(FlowLayout())
topPanel.add(JLabel("${TableData.npcNames[npc.id]}[${npc.id}]"))
val deleteButton = ImgButton(Image.DELETE_HI, Image.DELTE_LO)
topPanel.add(deleteButton)
val bottomPanel = JPanel(FlowLayout())
bottomPanel.add(JLabel("Direction [${spawnArrows[npc.spawnDirection]}] Walks? ${npc.canWalk}"))
add(topPanel, BorderLayout.NORTH)
add(JLabel("{${npc.location.x}, ${npc.location.y}, ${npc.location.z}}", SwingConstants.CENTER), BorderLayout.CENTER)
add(bottomPanel, BorderLayout.SOUTH)
minimumSize = Dimension(300, 65)
preferredSize = Dimension(300, 65)
maximumSize = Dimension(300, 65)
deleteButton.onClick {
Rs2MapEditor.npcs!!.remove(npc)
parent.remove(this)
parent.repaint()
Rs2MapEditor.npcRows.remove(this)
if(Rs2MapEditor.npcs!!.filter { it.location.x == npc.location.x && it.location.y == npc.location.y }.isEmpty()){
Rs2MapEditor.componentPointMap.filter { it.key.x == npc.location.localCoords[0] && it.key.y == npc.location.localCoords[1] }.forEach { (_,cell) ->
cell.components.forEach { c ->
if(c is JLabel) cell.remove(c)
}
cell.repaint()
Rs2MapEditor.npcsUpdated = true
}
}
}
addMouseListener(object : MouseAdapter(){
val border = MatteBorder(1, 1, 1, 1, Color.YELLOW)
val defaultBorder = MatteBorder(1, 1, 1, 1, Color.GRAY)
override fun mouseEntered(e: MouseEvent?) {
super.mouseEntered(e)
Rs2MapEditor.componentPointMap.filter { it.key.x == npc.location.localCoords[0] && it.key.y == npc.location.localCoords[1] }.forEach { it.value.border = border }
}
override fun mouseExited(e: MouseEvent?) {
super.mouseExited(e)
Rs2MapEditor.componentPointMap.filter { it.key.x == npc.location.localCoords[0] && it.key.y == npc.location.localCoords[1] }.forEach{ it.value.border = defaultBorder }
}
})
}
companion object {
val spawnArrows = arrayOf("","","","","","","","")
}
}
}

View file

@ -0,0 +1,16 @@
package ui
import javax.swing.JButton
class PlaneButton(val plane: Int) : JButton(plane.toString()){
init {
addActionListener {
if(Rs2MapEditor.plane != this.plane){
Rs2MapEditor.plane = this.plane
Rs2MapEditor.npcPanel.redrawRows()
Rs2MapEditor.itemPanel.redrawRows()
Rs2MapEditor.mapPanel.repaintMap()
}
}
}
}

View file

@ -0,0 +1,80 @@
package ui
import cacheops.cache.definition.decoder.MapTileParser
import java.awt.Color
import java.awt.Dimension
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import javax.swing.BorderFactory
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.SwingUtilities
import javax.swing.border.Border
import javax.swing.border.MatteBorder
class SelectableUnderlayCell(color: Color, size: Int, val id: Any) : JPanel() {
init {
when (id) {
is Int -> {
background = color
}
else -> {
background = color
border = BorderFactory.createDashedBorder(Color.GREEN)
}
}
val text = JLabel("$id")
text.foreground = Color((color.rgb).inv()).brighter()
minimumSize = Dimension(size, size)
maximumSize = Dimension(size, size)
preferredSize = Dimension(size, size)
add(text)
addMouseListener(object : MouseAdapter() {
val border: Border = MatteBorder(1, 1, 1, 1, Color.GRAY)
val highlight: Border = MatteBorder(1, 1, 1, 1, Color.YELLOW)
val selectionBorder = MatteBorder(1, 1, 1, 1, Color.WHITE)
override fun mouseEntered(e: MouseEvent?) {
this@SelectableUnderlayCell.border = selectionBorder
Rs2MapEditor.colorPointMap.filter { it.value == id }.forEach{ Rs2MapEditor.componentPointMap[it.key]!!.border = highlight}
}
override fun mouseExited(e: MouseEvent?) {
this@SelectableUnderlayCell.border = null
Rs2MapEditor.colorPointMap.filter { it.value == id }.forEach{ Rs2MapEditor.componentPointMap[it.key]!!.border = border}
}
override fun mouseClicked(e: MouseEvent) {
if (SwingUtilities.isLeftMouseButton(e)) {
when (id) {
is Int -> {
if(Rs2MapEditor.selectedUnderlayId == id){
Rs2MapEditor.state = EditorState.NONE
} else {
Rs2MapEditor.state = EditorState.SET_UNDERLAY
Rs2MapEditor.selectedUnderlayId = id
}
Rs2MapEditor.statusLabel.text = "<html>Region: ${Rs2MapEditor.region} | " +
"Local Coordinates: [${Rs2MapEditor.selectedPointX}, ${Rs2MapEditor.selectedPointY}, ${Rs2MapEditor.plane}] | " +
"Global Coordinates: [${MapTileParser.coordinateX(Rs2MapEditor.selectedPointX)}, ${
MapTileParser.coordinateX(
Rs2MapEditor.selectedPointY
)
}, ${Rs2MapEditor.plane}] | " +
"Viewing Underlay: ${
MapTileParser.definition.getTile(
Rs2MapEditor.selectedPointX,
Rs2MapEditor.selectedPointY, 0).underlayId - 1} | " +
"Selected Underlay: ${if (Rs2MapEditor.selectedUnderlayId == null) "<font color='red'>No underlay selected!</font>" else "${Rs2MapEditor.selectedUnderlayId}"}</html>"
}
else -> {
println("User trying to add new underlay")
}
}
}
}
})
}
}

View file

@ -0,0 +1,16 @@
package ui
import java.awt.BorderLayout
import java.awt.Color
import javax.swing.JPanel
import javax.swing.SwingConstants
class TileInformationPanel : JPanel() {
init {
Rs2MapEditor.underlayInfo.foreground = Color.white
Rs2MapEditor.underlayInfo.verticalAlignment = SwingConstants.TOP
Rs2MapEditor.underlayInfo.horizontalAlignment = SwingConstants.CENTER
layout = BorderLayout()
add(Rs2MapEditor.underlayInfo)
}
}

View file

@ -0,0 +1,15 @@
package ui
import java.awt.Color
import javax.swing.JPanel
class UnderlaySelectionPanel : JPanel() {
init {
Rs2MapEditor.underlayMap.forEach {
val underlay = SelectableUnderlayCell(it.value.getRGB(), 30, it.key)
add(underlay)
}
val addAnUnderlay = SelectableUnderlayCell(Color.darkGray, 30, "+")
add(addAnUnderlay)
}
}

View file

@ -0,0 +1,185 @@
package worldmap
import cacheops.cache.definition.data.OverlayDefinition
import cacheops.cache.definition.decoder.BlendedTextureDecoder
import cacheops.cache.definition.decoder.FloorOverlayConfiguration
import kotlin.math.pow
object OverlayHandler {
var blendedOverlayColors: IntArray = IntArray(FloorOverlayConfiguration.floorOverlays.size + 1)
var p: IntArray = IntArray(65536)
var f_l = (Math.random() * 11.0).toInt() - 5
var n = (Math.random() * 17.0).toInt() - 8
fun init() {
f(0)
f_l += -2 + (5.0 * Math.random()).toInt()
if (f_l < -8) {
f_l = -8
}
n += -2 + (Math.random() * 5.0).toInt()
if (f_l > 8) {
f_l = 8
}
if (n < -16) {
n = -16
}
if (n > 16) {
n = 16
}
setOverlayColorArray(((f_l shr 2) shl 10), n shr 1)
}
fun setOverlayColorArray(randomColorOffset1: Int, randomColorOffset2: Int) {
for (overlayId in 0 until FloorOverlayConfiguration.floorOverlays.size) {
blendedOverlayColors[overlayId + 1] = getOverlayColor(overlayId,randomColorOffset1,randomColorOffset2)
}
}
fun getOverlayColor(id: Int, colorOffset1: Int, colorOffset2: Int): Int {
val floDefinition: OverlayDefinition = FloorOverlayConfiguration.floorOverlays[id] ?: return 0
var floorOverlayTexture = floDefinition.texture
if (floorOverlayTexture >= 0 && BlendedTextureDecoder.blendedTextureDef[floorOverlayTexture]!!.renderOnMap) {
floorOverlayTexture = -1
}
val negativeRGBColor: Int
if (floDefinition.blendColor >= 0) {
val floorOverlayBlendColor = floDefinition.blendColor
var offsetBlendedValue = ((floorOverlayBlendColor and 0x7F) + colorOffset2)
if (offsetBlendedValue < 0) {
offsetBlendedValue = 0
} else if (offsetBlendedValue > 127) {
offsetBlendedValue = 127
}
val combinedBlendedValue = ((floorOverlayBlendColor + (colorOffset1 and 0xfc00) + ((floorOverlayBlendColor and 0x380))) + offsetBlendedValue)
negativeRGBColor = (0xffffff.inv() or p[colorFunc2(colorFunc1(96, 2, combinedBlendedValue),-2045205981).toInt() and 0xffff])
} else if (floorOverlayTexture >= 0) {
negativeRGBColor = (0xffffff.inv() or p[colorFunc2(colorFunc1(96, 2, BlendedTextureDecoder.blendedTextureDef[floorOverlayTexture]!!.blendedColor),-2045205981).toInt() and 0xffff])
} else if (floDefinition.color == -1) {
negativeRGBColor = 0
} else {
val floorOverlayColor = floDefinition.color
var offsetColorValue = ((floorOverlayColor and 0x7f) + colorOffset2)
if (offsetColorValue < 0) {
offsetColorValue = 0
} else if (offsetColorValue > 127) {
offsetColorValue = 127
}
val combinedColorValue = (((colorOffset1 and 0xfc00) + floorOverlayColor) + ((floorOverlayColor and 0x380) + offsetColorValue))
negativeRGBColor = (0xffffff.inv() or p[colorFunc2(colorFunc1(96, 2, combinedColorValue),-2045205981).toInt() and 0xffff])
}
return negativeRGBColor
}
fun colorFunc1(i: Int, i_1_: Int, i_2_: Int): Int {
var i = i
if (i_1_ != 2) {
return 64
}
if (i_2_ == -2) {
return 12345678
}
if (i_2_ == -1) {
if (i >= 2) {
if (i > 126) {
i = 126
}
} else {
i = 2
}
return i
}
i = i * (i_2_ and 0x7f) shr 7
if (i < 2) {
i = 2
} else if (i > 126) {
i = 126
}
return (0xff80 and i_2_) + i
}
fun colorFunc2(i: Int, i_1_: Int): Short {
return try {
val i_2_ = ((0xfddc and i) shr 10)
if (i_1_ != -2045205981) {
return 123.toShort()
}
var i_3_ = 0x384 and i shr 3
val i_4_ = 0x7f and i
i_3_ = if (i_4_ <= 64) i_4_ * i_3_ shr 7 else (127 - i_4_) * i_3_ shr 7
val i_5_ = i_3_ + i_4_
var i_6_: Int
do {
if (i_5_ == 0) {
i_6_ = i_3_ shl 1
if (!true) {
break
}
}
i_6_ = (i_3_ shl 8) / i_5_
} while (false)
(i_5_ or (i_2_ shl 10 or i_6_ shr 4 shl 7)).toShort()
} catch (runtimeexception: RuntimeException) {
throw error("fuk")
}
}
fun f(i: Int) {
val d = -0.015 + 0.03 * Math.random() + 0.7
var i_7_ = i
for (i_8_ in 0..511) {
val f = (0.0078125f + (i_8_ shr 3).toFloat() / 64.0f) * 360.0f
val f_9_ = (i_8_ and 0x7).toFloat() / 8.0f + 0.0625f
for (i_10_ in 0..127) {
val f_11_ = i_10_.toFloat() / 128.0f
var f_12_ = 0.0f
var f_13_ = 0.0f
var f_14_ = 0.0f
val f_15_ = f / 60.0f
val i_16_ = f_15_.toInt()
val i_17_ = i_16_ % 6
val f_18_ = f_15_ - i_16_.toFloat()
val f_19_ = f_11_ * (1.0f - f_9_)
val f_20_ = f_11_ * (-(f_18_ * f_9_) + 1.0f)
val f_21_ = f_11_ * (-(f_9_ * (-f_18_ + 1.0f)) + 1.0f)
if (i_17_ == 0) {
f_13_ = f_21_
f_14_ = f_19_
f_12_ = f_11_
} else if (i_17_ == 1) {
f_14_ = f_19_
f_13_ = f_11_
f_12_ = f_20_
} else if (i_17_ == 2) {
f_14_ = f_21_
f_13_ = f_11_
f_12_ = f_19_
} else if (i_17_ == 3) {
f_13_ = f_20_
f_12_ = f_19_
f_14_ = f_11_
} else if (i_17_ == 4) {
f_13_ = f_19_
f_12_ = f_21_
f_14_ = f_11_
} else if (i_17_ == 5) {
f_12_ = f_11_
f_13_ = f_19_
f_14_ = f_20_
}
f_12_ = f_12_.toDouble().pow(d).toFloat()
f_13_ = f_13_.toDouble().pow(d).toFloat()
f_14_ = f_14_.toDouble().pow(d).toFloat()
val i_22_ = (f_12_ * 256.0f).toInt()
val i_23_ = (f_13_ * 254.0f).toInt()
val i_24_ = (f_14_ * 256.0f).toInt()
val i_25_ = i_24_ + ((i_23_ shl 8) - 16777216 + (i_22_ shl 16))
p[i_7_++] = i_25_
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B