Repository reorganisation
Unified kotlin and java into just src/main Unified the rs09 and core packages Took all content out of the core package, and placed it into the new content package Reorganised all source code relating to content to be easier to find and explore
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package core
|
||||
|
||||
import org.json.simple.JSONObject
|
||||
import core.ServerStore.Companion.getInt
|
||||
|
||||
object GlobalStats {
|
||||
|
||||
@JvmStatic
|
||||
fun incrementDeathCount(){
|
||||
getDailyDeathArchive()["players"] = getDailyDeathArchive().getInt("players") + 1
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun incrementDailyCowDeaths(){
|
||||
getDailyDeathArchive()["lumbridge-cows"] = getDailyDeathArchive().getInt("lumbridge-cows") + 1
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun incrementGuardPickpockets(){
|
||||
getGuardPickpocketArchive()["count"] = getGuardPickpocketArchive().getInt("count") + 1
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDailyGuardPickpockets(): Int {
|
||||
return getGuardPickpocketArchive().getInt("count")
|
||||
}
|
||||
|
||||
fun getDailyDeaths(): Int {
|
||||
return getDailyDeathArchive().getInt("players")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDailyCowDeaths(): Int {
|
||||
return getDailyDeathArchive().getInt("lumbridge-cows")
|
||||
}
|
||||
|
||||
private fun getDailyDeathArchive(): JSONObject {
|
||||
return ServerStore.getArchive("daily-deaths-global")
|
||||
}
|
||||
|
||||
private fun getGuardPickpocketArchive(): JSONObject {
|
||||
return ServerStore.getArchive("daily-guard-pickpockets")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package core
|
||||
|
||||
import core.game.world.map.Location
|
||||
import java.io.File
|
||||
|
||||
class JSONUtils {
|
||||
companion object {
|
||||
|
||||
|
||||
/**
|
||||
* Parses a location from the format "x,y,z"
|
||||
* @author Ceikry
|
||||
* @param locString The string to parse
|
||||
* @return Location
|
||||
*/
|
||||
@JvmStatic
|
||||
fun parseLocation(locString: String): Location {
|
||||
val locTokens = locString.split(",").map { it.toInt() }
|
||||
return Location(locTokens[0], locTokens[1], locTokens[2])
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a path string
|
||||
* @author Ceikry
|
||||
* @param pathString The string to parse
|
||||
* @return a String with the proper file separators for the current OS.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun parsePath(pathString: String): String {
|
||||
var pathTokens: List<String>? = null
|
||||
if(pathString.contains("/"))
|
||||
pathTokens = pathString.split("/")
|
||||
else if(pathString.contains("\\"))
|
||||
pathTokens = pathString.split("\\")
|
||||
|
||||
pathTokens ?: return pathString //return the initial pathString if path does not contain file separators.
|
||||
var pathProduct = ""
|
||||
for(token in pathTokens){
|
||||
if(token != "")
|
||||
pathProduct += "$token${File.separator}"
|
||||
}
|
||||
|
||||
return pathProduct
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package core
|
||||
|
||||
import core.game.system.SystemManager
|
||||
import core.game.system.SystemState
|
||||
import core.net.NioReactor
|
||||
import core.tools.TimeStamp
|
||||
import kotlinx.coroutines.*
|
||||
import core.tools.SystemLogger
|
||||
import core.game.system.config.ServerConfigParser
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.repository.Repository
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.lang.management.ThreadMXBean
|
||||
import java.net.BindException
|
||||
import java.util.*
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
|
||||
/**
|
||||
* The main class, for those that are unable to read the class' name.
|
||||
* @author Emperor
|
||||
* @author Ceikry
|
||||
*/
|
||||
object Server {
|
||||
/**
|
||||
* The time stamp of when the server started running.
|
||||
*/
|
||||
@JvmField
|
||||
var startTime: Long = 0
|
||||
|
||||
var lastHeartbeat = System.currentTimeMillis()
|
||||
|
||||
@JvmStatic
|
||||
var running = false
|
||||
|
||||
/**
|
||||
* The NIO reactor.
|
||||
*/
|
||||
@JvmStatic
|
||||
var reactor: NioReactor? = null
|
||||
|
||||
/**
|
||||
* The main method, in this method we load background utilities such as
|
||||
* cache and our world, then end with starting networking.
|
||||
* @param args The arguments cast on runtime.
|
||||
* @throws Throwable When an exception occurs.
|
||||
*/
|
||||
@Throws(Throwable::class)
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
if (args.isNotEmpty()) {
|
||||
SystemLogger.logInfo(this::class.java, "Using config file: ${args[0]}")
|
||||
ServerConfigParser.parse(args[0])
|
||||
} else {
|
||||
SystemLogger.logInfo(this::class.java, "Using config file: ${"worldprops" + File.separator + "default.conf"}")
|
||||
ServerConfigParser.parse("worldprops" + File.separator + "default.conf")
|
||||
}
|
||||
startTime = System.currentTimeMillis()
|
||||
val t = TimeStamp()
|
||||
GameWorld.prompt(true)
|
||||
Runtime.getRuntime().addShutdownHook(ServerConstants.SHUTDOWN_HOOK)
|
||||
SystemLogger.logInfo(this::class.java, "Starting networking...")
|
||||
try {
|
||||
reactor = NioReactor.configure(43594 + GameWorld.settings?.worldId!!)
|
||||
reactor!!.start()
|
||||
} catch (e: BindException) {
|
||||
SystemLogger.logErr(this::class.java, "Port " + (43594 + GameWorld.settings?.worldId!!) + " is already in use!")
|
||||
throw e
|
||||
}
|
||||
//WorldCommunicator.connect()
|
||||
SystemLogger.logInfo(this::class.java, GameWorld.settings?.name + " flags " + GameWorld.settings?.toString())
|
||||
SystemLogger.logInfo(this::class.java, GameWorld.settings?.name + " started in " + t.duration(false, "") + " milliseconds.")
|
||||
val scanner = Scanner(System.`in`)
|
||||
|
||||
running = true
|
||||
GlobalScope.launch {
|
||||
while(scanner.hasNextLine()){
|
||||
val command = scanner.nextLine()
|
||||
when(command){
|
||||
"stop" -> exitProcess(0)
|
||||
"players" -> System.out.println("Players online: " + (Repository.LOGGED_IN_PLAYERS.size))
|
||||
"update" -> SystemManager.flag(SystemState.UPDATING)
|
||||
"help","commands" -> printCommands()
|
||||
"restartworker" -> SystemManager.flag(SystemState.ACTIVE)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ServerConstants.WATCHDOG_ENABLED) {
|
||||
GlobalScope.launch {
|
||||
delay(20000)
|
||||
while (running) {
|
||||
if (System.currentTimeMillis() - lastHeartbeat > 7200 && running) {
|
||||
SystemLogger.logErr(this::class.java, "Triggering reboot due to heartbeat timeout")
|
||||
SystemLogger.logErr(this::class.java, "Creating thread dump...")
|
||||
val dump = threadDump(true, true)
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
FileWriter("latestdump.txt").use {
|
||||
|
||||
if (dump != null) {
|
||||
it.write(dump)
|
||||
}
|
||||
|
||||
it.flush()
|
||||
it.close()
|
||||
}
|
||||
}
|
||||
|
||||
if (!SystemManager.isTerminated())
|
||||
exitProcess(0)
|
||||
}
|
||||
delay(625)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun heartbeat() {
|
||||
lastHeartbeat = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
fun printCommands(){
|
||||
println("stop - stop the server (saves all accounts and such)")
|
||||
println("players - show online player count")
|
||||
println("update - initiate an update with a countdown visible to players")
|
||||
println("help, commands - show this")
|
||||
println("restartworker - Reboots the major update worker in case of a travesty.")
|
||||
}
|
||||
|
||||
fun autoReconnect() {
|
||||
/*SystemLogger.log("Attempting autoreconnect of server")
|
||||
WorldCommunicator.connect()*/
|
||||
}
|
||||
/**
|
||||
* Gets the startTime.
|
||||
* @return the startTime
|
||||
*/
|
||||
fun getStartTime(): Long {
|
||||
return startTime
|
||||
}
|
||||
|
||||
private fun threadDump(lockedMonitors: Boolean, lockedSynchronizers: Boolean): String? {
|
||||
val threadDump = StringBuffer(System.lineSeparator())
|
||||
val threadMXBean: ThreadMXBean = ManagementFactory.getThreadMXBean()
|
||||
for (threadInfo in threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)) {
|
||||
threadDump.append(threadInfo.toString())
|
||||
}
|
||||
return threadDump.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bastartTime.ZZ
|
||||
* @param startTime the startTime to set.
|
||||
*/
|
||||
fun setStartTime(startTime: Long) {
|
||||
Server.startTime = startTime
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
package core
|
||||
|
||||
import core.game.system.SystemShutdownHook
|
||||
import core.game.system.mysql.SQLManager
|
||||
import core.game.world.map.Location
|
||||
import core.tools.mysql.Database
|
||||
import core.tools.secondsToTicks
|
||||
import org.json.simple.JSONObject
|
||||
import java.io.File
|
||||
import java.math.BigInteger
|
||||
|
||||
/**
|
||||
* A class holding various variables for the server.
|
||||
* @author Ceikry
|
||||
*/
|
||||
class ServerConstants {
|
||||
companion object {
|
||||
@JvmField
|
||||
var SHUTDOWN_HOOK: Thread = Thread(SystemShutdownHook())
|
||||
|
||||
@JvmField
|
||||
var DATA_PATH: String? = null
|
||||
|
||||
//path to the cache
|
||||
@JvmField
|
||||
var CACHE_PATH: String? = null
|
||||
|
||||
//path for the server store (obsolete, but kept for the sake of system sanity.)
|
||||
@JvmField
|
||||
var STORE_PATH: String? = null
|
||||
|
||||
//path for player saves
|
||||
@JvmField
|
||||
var PLAYER_SAVE_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var PLAYER_ATTRIBUTE_PATH = "ish";
|
||||
|
||||
//path to the various config files, such as npc_spawns.json
|
||||
var CONFIG_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var GRAND_EXCHANGE_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var RDT_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var OBJECT_PARSER_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var SCRIPTS_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var DIALOGUE_SCRIPTS_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var LOGS_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var BOT_DATA_PATH: String? = null
|
||||
|
||||
//the max number of players.
|
||||
@JvmField
|
||||
var MAX_PLAYERS = 0
|
||||
|
||||
//the max number of NPCs
|
||||
@JvmField
|
||||
var MAX_NPCS = 0
|
||||
|
||||
//the location where new players are placed on login.
|
||||
@JvmField
|
||||
var START_LOCATION: Location? = null
|
||||
|
||||
//Location for all home teleports/respawn location
|
||||
@JvmField
|
||||
var HOME_LOCATION: Location? = null
|
||||
|
||||
//the name for the database
|
||||
@JvmField
|
||||
var DATABASE_NAME: String? = null
|
||||
|
||||
//username for the database
|
||||
@JvmField
|
||||
var DATABASE_USER: String? = null
|
||||
|
||||
//password for the database
|
||||
@JvmField
|
||||
var DATABASE_PASS: String? = null
|
||||
|
||||
//address for the database
|
||||
@JvmField
|
||||
var DATABASE_ADDRESS: String? = null
|
||||
|
||||
@JvmField
|
||||
var DATABASE_PORT: String? = null
|
||||
|
||||
@JvmField
|
||||
var WRITE_LOGS: Boolean = false
|
||||
|
||||
@JvmField
|
||||
var BANK_SIZE: Int = 496
|
||||
|
||||
@JvmField
|
||||
var GE_AUTOSAVE_FREQUENCY = secondsToTicks(3600) //1 hour
|
||||
|
||||
@JvmField
|
||||
var GE_AUTOSTOCK_ENABLED = false
|
||||
|
||||
//location names for the ::to command.
|
||||
val TELEPORT_DESTINATIONS = arrayOf(
|
||||
arrayOf(Location.create(2974, 4383, 2), "corp", "corporal", "corporeal"),
|
||||
arrayOf(Location.create(2659, 2649, 0), "pc", "pest control", "pest"),
|
||||
arrayOf(Location.create(3293, 3184, 0), "al kharid", "alkharid", "kharid"),
|
||||
arrayOf(Location.create(3222, 3217, 0), "lumbridge", "lumby"),
|
||||
arrayOf(Location.create(3110, 3168, 0), "wizard tower", "wizards tower", "tower", "wizards"),
|
||||
arrayOf(Location.create(3083, 3249, 0), "draynor", "draynor village"),
|
||||
arrayOf(Location.create(3019, 3244, 0), "port sarim", "sarim"),
|
||||
arrayOf(Location.create(2956, 3209, 0), "rimmington"),
|
||||
arrayOf(Location.create(2965, 3380, 0), "fally", "falador"),
|
||||
arrayOf(Location.create(2895, 3436, 0), "taverley"),
|
||||
arrayOf(Location.create(3080, 3423, 0), "barbarian village", "barb"),
|
||||
arrayOf(Location.create(3213, 3428, 0), "varrock"),
|
||||
arrayOf(Location.create(3164, 3485, 0), "grand exchange", "ge"),
|
||||
arrayOf(Location.create(2917, 3175, 0), "karamja"),
|
||||
arrayOf(Location.create(2450, 5165, 0), "tzhaar"),
|
||||
arrayOf(Location.create(2795, 3177, 0), "brimhaven"),
|
||||
arrayOf(Location.create(2849, 2961, 0), "shilo village", "shilo"),
|
||||
arrayOf(Location.create(2605, 3093, 0), "yanille"),
|
||||
arrayOf(Location.create(2663, 3305, 0), "ardougne", "ardy"),
|
||||
arrayOf(Location.create(2450, 3422, 0), "gnome stronghold", "gnome"),
|
||||
arrayOf(Location.create(2730, 3485, 0), "camelot", "cammy", "seers"),
|
||||
arrayOf(Location.create(2805, 3435, 0), "catherby"),
|
||||
arrayOf(Location.create(2659, 3657, 0), "rellekka"),
|
||||
arrayOf(Location.create(2890, 3676, 0), "trollheim"),
|
||||
arrayOf(Location.create(2914, 3746, 0), "godwars", "gwd", "god wars"),
|
||||
arrayOf(Location.create(3180, 3684, 0), "bounty hunter", "bh"),
|
||||
arrayOf(Location.create(3272, 3687, 0), "clan wars", "clw"),
|
||||
arrayOf(Location.create(3090, 3957, 0), "mage arena", "mage", "magearena", "arena"),
|
||||
arrayOf(Location.create(3069, 10257, 0), "king black dragon", "kbd"),
|
||||
arrayOf(Location.create(3359, 3416, 0), "digsite"),
|
||||
arrayOf(Location.create(3488, 3489, 0), "canifis"),
|
||||
arrayOf(Location.create(3428, 3526, 0), "slayer tower", "slayer"),
|
||||
arrayOf(Location.create(3502, 9483, 2), "kalphite queen", "kq", "kalphite hive", "kalphite"),
|
||||
arrayOf(Location.create(3233, 2913, 0), "pyramid"),
|
||||
arrayOf(Location.create(3419, 2917, 0), "nardah"),
|
||||
arrayOf(Location.create(3482, 3090, 0), "uzer"),
|
||||
arrayOf(Location.create(3358, 2970, 0), "pollnivneach", "poln"),
|
||||
arrayOf(Location.create(3305, 2788, 0), "sophanem"),
|
||||
arrayOf(Location.create(2898, 3544, 0), "burthorpe", "burthorp"),
|
||||
arrayOf(Location.create(3088, 3491, 0), "edge", "edgeville"),
|
||||
arrayOf(Location.create(3169, 3034, 0), "bedabin"),
|
||||
arrayOf(Location.create(3565, 3289, 0), "barrows"),
|
||||
arrayOf(Location.create(3016, 3513, 0), "bkf", "black knights fortress"),
|
||||
arrayOf(Location.create(3052, 3481, 0), "monastery")
|
||||
)
|
||||
|
||||
@JvmField
|
||||
var DATABASE: Database? = null
|
||||
|
||||
//if SQL is enabled
|
||||
@JvmField
|
||||
var MYSQL = true
|
||||
|
||||
//the server name
|
||||
@JvmField
|
||||
var SERVER_NAME: String = ""
|
||||
|
||||
//The RSA_KEY for the server.
|
||||
@JvmField
|
||||
var EXPONENT = BigInteger("52317200263721308660411803146360972546561037484450290559823448967617618536819222494429186211525706853703641369936136465589036631055945454547936148730495933263344792588795811788941129493188907621550836988152620502378278134421731002382361670176785306598134280732756356458964850508114958769985438054979422820241")
|
||||
|
||||
//The MODULUS for the server.
|
||||
@JvmField
|
||||
var MODULUS = BigInteger("96982303379631821170939875058071478695026608406924780574168393250855797534862289546229721580153879336741968220328805101128831071152160922518190059946555203865621183480223212969502122536662721687753974815205744569357388338433981424032996046420057284324856368815997832596174397728134370577184183004453899764051")
|
||||
|
||||
/**
|
||||
* Parses a JSONObject and retrieves the values for all settings in this file.
|
||||
* @author Ceikry
|
||||
* @param data : The JSONObject to parse.
|
||||
*/
|
||||
fun parse(data: JSONObject) {
|
||||
MAX_PLAYERS = data["max_players"].toString().toInt()
|
||||
MAX_NPCS = data["max_npcs"].toString().toInt()
|
||||
|
||||
START_LOCATION = JSONUtils.parseLocation(data["new_player_location"].toString())
|
||||
HOME_LOCATION = JSONUtils.parseLocation(data["home_location"].toString())
|
||||
|
||||
DATA_PATH = JSONUtils.parsePath(data["data_path"].toString())
|
||||
CACHE_PATH = JSONUtils.parsePath(data["cache_path"].toString())
|
||||
STORE_PATH = JSONUtils.parsePath(data["store_path"].toString())
|
||||
PLAYER_SAVE_PATH = JSONUtils.parsePath(data["save_path"].toString())
|
||||
CONFIG_PATH = JSONUtils.parsePath(data["configs_path"].toString())
|
||||
PLAYER_ATTRIBUTE_PATH = PLAYER_SAVE_PATH + "attributes" + File.separator
|
||||
GRAND_EXCHANGE_DATA_PATH = JSONUtils.parsePath(data["grand_exchange_data_path"].toString())
|
||||
BOT_DATA_PATH = JSONUtils.parsePath(data["bot_data_path"].toString())
|
||||
RDT_DATA_PATH = JSONUtils.parsePath(data["rare_drop_table_path"].toString())
|
||||
OBJECT_PARSER_PATH = JSONUtils.parsePath(data["object_parser_path"].toString())
|
||||
SCRIPTS_PATH = JSONUtils.parsePath(data["scripts_path"].toString())
|
||||
DIALOGUE_SCRIPTS_PATH = JSONUtils.parsePath(data["dialogue_scripts_path"].toString())
|
||||
if(data.containsKey("logs_path")){
|
||||
LOGS_PATH = data["logs_path"].toString()
|
||||
}
|
||||
if(data.containsKey("writeLogs")){
|
||||
WRITE_LOGS = data["writeLogs"] as Boolean
|
||||
}
|
||||
|
||||
DATABASE_NAME = data["database_name"].toString()
|
||||
DATABASE_USER = data["database_username"].toString()
|
||||
DATABASE_PASS = data["database_password"].toString()
|
||||
DATABASE_ADDRESS = data["database_address"].toString()
|
||||
DATABASE_PORT = data["database_port"].toString()
|
||||
|
||||
DATABASE = Database(DATABASE_ADDRESS, DATABASE_NAME, DATABASE_USER, DATABASE_PASS)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package core
|
||||
|
||||
import core.game.system.SystemShutdownHook
|
||||
import core.game.world.map.Location
|
||||
import core.tools.mysql.Database
|
||||
import core.tools.secondsToTicks
|
||||
import java.math.BigInteger
|
||||
|
||||
/**
|
||||
* A class holding various variables for the server.
|
||||
* @author Ceikry
|
||||
*/
|
||||
class ServerConstants {
|
||||
companion object {
|
||||
var NOAUTH_DEFAULT_ADMIN: Boolean = true
|
||||
|
||||
@JvmField
|
||||
var DAILY_ACCOUNT_LIMIT = 3
|
||||
|
||||
@JvmField
|
||||
var REVENANT_POPULATION: Int = 30
|
||||
|
||||
@JvmField
|
||||
var BOTS_INFLUENCE_PRICE_INDEX = true
|
||||
|
||||
@JvmField
|
||||
var SHUTDOWN_HOOK: Thread = Thread(SystemShutdownHook())
|
||||
|
||||
@JvmField
|
||||
var ALLOW_GUI: Boolean = false
|
||||
|
||||
@JvmField
|
||||
var DATA_PATH: String? = null
|
||||
|
||||
//path to the cache
|
||||
@JvmField
|
||||
var CACHE_PATH: String? = null
|
||||
|
||||
//path for the server store
|
||||
@JvmField
|
||||
var STORE_PATH: String? = null
|
||||
|
||||
//path for player saves
|
||||
@JvmField
|
||||
var PLAYER_SAVE_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var PLAYER_ATTRIBUTE_PATH = "ish";
|
||||
|
||||
//path to the various config files, such as npc_spawns.json
|
||||
var CONFIG_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var GRAND_EXCHANGE_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var RDT_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var OBJECT_PARSER_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var SCRIPTS_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var DIALOGUE_SCRIPTS_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var LOGS_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var BOT_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var CELEDT_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var USDT_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var HDT_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var GDT_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var RSDT_DATA_PATH: String? = null
|
||||
|
||||
@JvmField
|
||||
var ASDT_DATA_PATH: String? = null
|
||||
|
||||
//the max number of players.
|
||||
@JvmField
|
||||
var MAX_PLAYERS = 2000
|
||||
|
||||
//the max number of NPCs
|
||||
@JvmField
|
||||
var MAX_NPCS = 32000
|
||||
|
||||
//the location where new players are placed on login.
|
||||
@JvmField
|
||||
var START_LOCATION: Location? = null
|
||||
|
||||
//Location for all home teleports/respawn location
|
||||
@JvmField
|
||||
var HOME_LOCATION: Location? = null
|
||||
|
||||
//the name for the database
|
||||
@JvmField
|
||||
var DATABASE_NAME: String? = null
|
||||
|
||||
//username for the database
|
||||
@JvmField
|
||||
var DATABASE_USER: String? = null
|
||||
|
||||
//password for the database
|
||||
@JvmField
|
||||
var DATABASE_PASS: String? = null
|
||||
|
||||
//address for the database
|
||||
@JvmField
|
||||
var DATABASE_ADDRESS: String? = null
|
||||
|
||||
@JvmField
|
||||
var DATABASE_PORT: String? = null
|
||||
|
||||
@JvmField
|
||||
var WRITE_LOGS: Boolean = false
|
||||
|
||||
@JvmField
|
||||
var BANK_SIZE: Int = 496
|
||||
|
||||
@JvmField
|
||||
var BANK_BOOTH_QUICK_OPEN: Boolean = false
|
||||
|
||||
@JvmField
|
||||
var BANK_BOOTH_NOTE_ENABLED: Boolean = true
|
||||
|
||||
@JvmField
|
||||
var BANK_BOOTH_NOTE_UIM: Boolean = true
|
||||
|
||||
@JvmField
|
||||
var GE_AUTOSAVE_FREQUENCY = secondsToTicks(3600) //1 hour
|
||||
|
||||
@JvmField
|
||||
var GE_AUTOSTOCK_ENABLED = false
|
||||
|
||||
@JvmField
|
||||
var MS_SECRET_KEY = ""
|
||||
|
||||
@JvmField
|
||||
var LOG_CUTSCENE = true
|
||||
|
||||
@JvmField
|
||||
var RULES_AND_INFO_ENABLED = true
|
||||
|
||||
@JvmField
|
||||
var WATCHDOG_ENABLED = true
|
||||
|
||||
@JvmField
|
||||
var I_AM_A_CHEATER = false
|
||||
|
||||
//location names for the ::to command.
|
||||
val TELEPORT_DESTINATIONS = arrayOf(
|
||||
arrayOf(Location.create(2974, 4383, 2), "corp", "corporal", "corporeal"),
|
||||
arrayOf(Location.create(2659, 2649, 0), "pc", "pest control", "pest"),
|
||||
arrayOf(Location.create(3293, 3184, 0), "al kharid", "alkharid", "kharid"),
|
||||
arrayOf(Location.create(3222, 3217, 0), "lumbridge", "lumby"),
|
||||
arrayOf(Location.create(3110, 3168, 0), "wizard tower", "wizards tower", "tower", "wizards"),
|
||||
arrayOf(Location.create(3083, 3249, 0), "draynor", "draynor village"),
|
||||
arrayOf(Location.create(3019, 3244, 0), "port sarim", "sarim"),
|
||||
arrayOf(Location.create(2956, 3209, 0), "rimmington"),
|
||||
arrayOf(Location.create(2965, 3380, 0), "fally", "falador"),
|
||||
arrayOf(Location.create(2895, 3436, 0), "taverley"),
|
||||
arrayOf(Location.create(3080, 3423, 0), "barbarian village", "barb"),
|
||||
arrayOf(Location.create(3213, 3428, 0), "varrock"),
|
||||
arrayOf(Location.create(3164, 3485, 0), "grand exchange", "ge"),
|
||||
arrayOf(Location.create(2917, 3175, 0), "karamja"),
|
||||
arrayOf(Location.create(2450, 5165, 0), "tzhaar"),
|
||||
arrayOf(Location.create(2795, 3177, 0), "brimhaven"),
|
||||
arrayOf(Location.create(2849, 2961, 0), "shilo village", "shilo"),
|
||||
arrayOf(Location.create(2605, 3093, 0), "yanille"),
|
||||
arrayOf(Location.create(2663, 3305, 0), "ardougne", "ardy"),
|
||||
arrayOf(Location.create(2450, 3422, 0), "gnome stronghold", "gnome"),
|
||||
arrayOf(Location.create(2730, 3485, 0), "camelot", "cammy", "seers"),
|
||||
arrayOf(Location.create(2805, 3435, 0), "catherby"),
|
||||
arrayOf(Location.create(2659, 3657, 0), "rellekka"),
|
||||
arrayOf(Location.create(2890, 3676, 0), "trollheim"),
|
||||
arrayOf(Location.create(2914, 3746, 0), "godwars", "gwd", "god wars"),
|
||||
arrayOf(Location.create(3180, 3684, 0), "bounty hunter", "bh"),
|
||||
arrayOf(Location.create(3272, 3687, 0), "clan wars", "clw"),
|
||||
arrayOf(Location.create(3090, 3957, 0), "mage arena", "mage", "magearena", "arena"),
|
||||
arrayOf(Location.create(3069, 10257, 0), "king black dragon", "kbd"),
|
||||
arrayOf(Location.create(3359, 3416, 0), "digsite"),
|
||||
arrayOf(Location.create(3488, 3489, 0), "canifis"),
|
||||
arrayOf(Location.create(3428, 3526, 0), "slayer tower", "slayer"),
|
||||
arrayOf(Location.create(3502, 9483, 2), "kalphite queen", "kq", "kalphite hive", "kalphite"),
|
||||
arrayOf(Location.create(3233, 2913, 0), "pyramid"),
|
||||
arrayOf(Location.create(3419, 2917, 0), "nardah"),
|
||||
arrayOf(Location.create(3482, 3090, 0), "uzer"),
|
||||
arrayOf(Location.create(3358, 2970, 0), "pollnivneach", "poln"),
|
||||
arrayOf(Location.create(3305, 2788, 0), "sophanem"),
|
||||
arrayOf(Location.create(2898, 3544, 0), "burthorpe", "burthorp"),
|
||||
arrayOf(Location.create(3088, 3491, 0), "edge", "edgeville"),
|
||||
arrayOf(Location.create(3169, 3034, 0), "bedabin"),
|
||||
arrayOf(Location.create(3565, 3289, 0), "barrows"),
|
||||
arrayOf(Location.create(3016, 3513, 0), "bkf", "black knights fortress"),
|
||||
arrayOf(Location.create(3052, 3481, 0), "monastery"),
|
||||
arrayOf(Location.create(1945, 4959, 0), "blast furnace", "blast"),
|
||||
arrayOf(Location.create(2408, 4449, 0), "zanaris"),
|
||||
arrayOf(Location.create(3656, 3517, 0), "ectofuntus", "ecto"),
|
||||
arrayOf(Location.create(2408, 4449, 0), "tower of life lower"),
|
||||
arrayOf(Location.create(2894, 4756, 0), "test area"),
|
||||
arrayOf(Location.create(2722, 4886, 0), "quest the golem 1"),
|
||||
arrayOf(Location.create(2704, 5349, 0), "dorgeshuun", "dorg"),
|
||||
arrayOf(Location.create(2711, 10132, 0), "brine rats"),
|
||||
arrayOf(Location.create(2328, 3677, 0), "piscatoris"),
|
||||
arrayOf(Location.create(2660, 3158, 0), "fishing trawler", "trawler"),
|
||||
arrayOf(Location.create(2800, 3667, 0), "mountain camp"),
|
||||
arrayOf(Location.create(2575, 3250, 0), "clocktower")
|
||||
)
|
||||
//arrayOf(Location.create(0, 0, 0), ""),
|
||||
|
||||
@JvmField
|
||||
var DATABASE: Database? = null
|
||||
|
||||
//if SQL is enabled
|
||||
@JvmField
|
||||
var MYSQL = true
|
||||
|
||||
//the server name
|
||||
@JvmField
|
||||
var SERVER_NAME: String = ""
|
||||
|
||||
//the server's grand exchange name
|
||||
@JvmField
|
||||
var SERVER_GE_NAME: String = ""
|
||||
|
||||
//The RSA_KEY for the server.
|
||||
@JvmField
|
||||
var EXPONENT = BigInteger("52317200263721308660411803146360972546561037484450290559823448967617618536819222494429186211525706853703641369936136465589036631055945454547936148730495933263344792588795811788941129493188907621550836988152620502378278134421731002382361670176785306598134280732756356458964850508114958769985438054979422820241")
|
||||
|
||||
//The MODULUS for the server.
|
||||
@JvmField
|
||||
var MODULUS = BigInteger("96982303379631821170939875058071478695026608406924780574168393250855797534862289546229721580153879336741968220328805101128831071152160922518190059946555203865621183480223212969502122536662721687753974815205744569357388338433981424032996046420057284324856368815997832596174397728134370577184183004453899764051")
|
||||
|
||||
@JvmField
|
||||
var DAILY_RESTART = false
|
||||
|
||||
@JvmField
|
||||
var DISCORD_GE_WEBHOOK = ""
|
||||
|
||||
@JvmField
|
||||
var DISCORD_MOD_WEBHOOK = ""
|
||||
|
||||
@JvmField
|
||||
var PRELOAD_MAP = false
|
||||
|
||||
@JvmField
|
||||
var USE_AUTH = false
|
||||
|
||||
@JvmField
|
||||
var PERSIST_ACCOUNTS = false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package core
|
||||
|
||||
import core.api.PersistWorld
|
||||
import core.api.getItemName
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import org.json.simple.JSONArray
|
||||
import org.json.simple.JSONObject
|
||||
import org.json.simple.parser.JSONParser
|
||||
import core.tools.SystemLogger
|
||||
import core.tools.SystemLogger.logShutdown
|
||||
import core.tools.SystemLogger.logStartup
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import javax.script.ScriptEngineManager
|
||||
|
||||
class ServerStore : PersistWorld {
|
||||
override fun parse() {
|
||||
logStartup("Parsing server store...")
|
||||
val dir = File(ServerConstants.STORE_PATH!!)
|
||||
if(!dir.exists()){
|
||||
dir.mkdirs()
|
||||
return
|
||||
}
|
||||
|
||||
var parser: JSONParser
|
||||
var reader: FileReader
|
||||
|
||||
dir.listFiles()?.forEach { storeFile ->
|
||||
val key = storeFile.nameWithoutExtension
|
||||
|
||||
reader = FileReader(storeFile)
|
||||
parser = JSONParser()
|
||||
|
||||
try {
|
||||
val data = parser.parse(reader) as JSONObject
|
||||
fileMap[key] = data
|
||||
counter++
|
||||
} catch (e: Exception){
|
||||
SystemLogger.logErr(this::class.java, "Failed parsing ${storeFile.name} - stack trace below.")
|
||||
e.printStackTrace()
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
|
||||
logStartup("Initialized $counter store files.")
|
||||
}
|
||||
|
||||
override fun save() {
|
||||
logShutdown("Saving server store...")
|
||||
val dir = File(ServerConstants.DATA_PATH + File.separator + "serverstore")
|
||||
if(!dir.exists()){
|
||||
dir.mkdirs()
|
||||
return
|
||||
}
|
||||
|
||||
val manager = ScriptEngineManager()
|
||||
val scriptEngine = manager.getEngineByName("JavaScript")
|
||||
|
||||
fileMap.forEach { (name, data) ->
|
||||
val path = dir.absolutePath + File.separator + name + ".json"
|
||||
|
||||
scriptEngine.put("jsonString", data.toJSONString())
|
||||
scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)")
|
||||
val prettyPrintedJson = scriptEngine["result"] as String
|
||||
|
||||
FileWriter(path).use { it.write(prettyPrintedJson); it.flush(); it.close() }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val fileMap = HashMap<String,JSONObject>()
|
||||
var counter = 0
|
||||
|
||||
@JvmStatic
|
||||
fun getArchive(name: String): JSONObject {
|
||||
if(fileMap[name] == null){
|
||||
fileMap[name] = JSONObject()
|
||||
}
|
||||
|
||||
return fileMap[name]!!
|
||||
}
|
||||
|
||||
fun setArchive(name: String, data: JSONObject){
|
||||
fileMap[name] = data
|
||||
}
|
||||
|
||||
fun clearDailyEntries() {
|
||||
fileMap.keys.toTypedArray().forEach {
|
||||
if(it.toLowerCase().contains("daily")) fileMap[it]?.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun clearWeeklyEntries() {
|
||||
fileMap.keys.toTypedArray().forEach {
|
||||
if(it.toLowerCase().contains("weekly")) fileMap[it]?.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun JSONObject.getInt(key: String): Int {
|
||||
return when(val value = this[key]){
|
||||
is Long -> value.toInt()
|
||||
is Double -> value.toInt()
|
||||
is Float -> value.toInt()
|
||||
is Int -> value
|
||||
is Nothing -> 0
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun JSONObject.getString(key: String): String {
|
||||
return this[key] as? String ?: "nothing"
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun JSONObject.getLong(key: String): Long {
|
||||
return this[key] as? Long ?: 0L
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun JSONObject.getBoolean(key: String): Boolean {
|
||||
return this[key] as? Boolean ?: false
|
||||
}
|
||||
|
||||
fun List<Int>.toJSONArray(): JSONArray{
|
||||
val jArray = JSONArray()
|
||||
for(i in this){
|
||||
jArray.add(i)
|
||||
}
|
||||
return jArray
|
||||
}
|
||||
|
||||
inline fun <reified T> JSONObject.getList(key: String) : List<T> {
|
||||
val array = this[key] as? JSONArray ?: JSONArray()
|
||||
val list = ArrayList<T>()
|
||||
for(element in array) list.add(element as T)
|
||||
return list
|
||||
}
|
||||
|
||||
fun JSONObject.addToList(key: String, value: Any) {
|
||||
val array = this.getOrPut(key) {JSONArray()} as JSONArray
|
||||
array.add(value)
|
||||
}
|
||||
|
||||
/** NPCItemMemory
|
||||
* These next methods handle the NPCItemMemory database. these are server-stored JSON objects,
|
||||
* which are based on an npc and an item.
|
||||
* each NPC can have a JSON object for itself for any item.
|
||||
* the NPC Item object can store integer values for individual players, using their names as keys.
|
||||
* the first methods handle the serverstore filename and accessing the JSON object.
|
||||
* these methods are wrapped by more convenient ones that allow access for a particular player, see below.
|
||||
*/
|
||||
fun NPCItemFilename(npc: Int, item: Int, period: String = "daily"): String {
|
||||
val itemName = getItemName(item).lowercase().replace(" ","-")
|
||||
val npcName = NPC(npc).name.lowercase()
|
||||
return "$period-$npcName-$itemName"
|
||||
}
|
||||
fun NPCItemMemory(npc: Int, item: Int, period: String = "daily"): JSONObject {
|
||||
return getArchive(NPCItemFilename(npc,item,period))
|
||||
}
|
||||
|
||||
/** NPCItemMemory Player Access
|
||||
* These next functions handle individual player access to the NPC Item Memory database.
|
||||
* each of the functions has at least 3 mandatory arguments: npc, item, player.
|
||||
* These functions can be used to allow players to access a daily- or weekly-reset stock of a particular item overseen by a particular NPC.
|
||||
*
|
||||
* note that none of these functions perform tangible actions on the player.
|
||||
* whoever calls these functions is responsible for handling tangible actions like putting items in an inventory.
|
||||
* these functions simply return and update the NPCItemMemory database numbers in useful ways.
|
||||
*/
|
||||
|
||||
/** getNPCItemStock:
|
||||
* gets the available stock of a particular item at a particular NPC for a particular player.
|
||||
*/
|
||||
fun getNPCItemStock(npc: Int, item: Int, limit: Int, player: Player, period: String = "daily"): Int {
|
||||
val itemMemory = NPCItemMemory(npc,item)
|
||||
val key = player.name
|
||||
var stock = limit-itemMemory.getInt(key)
|
||||
stock = maxOf(stock,0)
|
||||
return stock
|
||||
}
|
||||
/** getNPCItemAmount:
|
||||
* gets the usable amount of a particular item from a particular npc for a particular player.
|
||||
* this is essentially just a requested amount cut to conform to stock and nonnegative requirements.
|
||||
* what this function does is it takes a requested amount, cuts it down to be equal to available stock if
|
||||
* available stock is less than the requested amount, and then additionally sets a minimum of 0.
|
||||
*/
|
||||
fun getNPCItemAmount(npc: Int, item: Int, limit: Int, player: Player, amount: Int, period: String = "daily"): Int {
|
||||
val stock = getNPCItemStock(npc,item,limit,player,period)
|
||||
var realamount = minOf(amount,stock)
|
||||
realamount = maxOf(realamount,0)
|
||||
return realamount
|
||||
}
|
||||
/** addNPCItemAmount:
|
||||
* this function updates the NPC Item Memory database entry for a particular player.
|
||||
* it is intended to be called after all the actions that use the number have been successfully completed.
|
||||
* this function will *add* the amount argument to the current npc item memory entry for that player. this means that
|
||||
* the amount argument is the amount to add, not the absolute final amount.
|
||||
* this function will handle correctly setting the limit and any other required semantics.
|
||||
*/
|
||||
fun addNPCItemAmount(npc: Int, item: Int, limit: Int, player: Player, amount: Int, period: String = "daily") {
|
||||
val itemMemory = NPCItemMemory(npc,item,period)
|
||||
val key = player.name
|
||||
var realamount = itemMemory.getInt(key) + amount
|
||||
realamount = minOf(realamount,limit)
|
||||
realamount = maxOf(realamount,0)
|
||||
itemMemory[key] = realamount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package core;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
public class Util {
|
||||
|
||||
/**
|
||||
* Capitalize the first letter of the string
|
||||
* @return Capitalized string
|
||||
*/
|
||||
public static String capitalize(String name) {
|
||||
if (name != null && name.length() != 0) {
|
||||
char[] chars = name.toCharArray();
|
||||
chars[0] = Character.toUpperCase(chars[0]);
|
||||
return new String(chars);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public static String strToEnum(String name) {
|
||||
name = name.toUpperCase();
|
||||
return name.replaceAll(" ", "_");
|
||||
}
|
||||
|
||||
public static String enumToString(String name) {
|
||||
name = name.toLowerCase();
|
||||
name = name.replaceAll("_", " ");
|
||||
return capitalize(name);
|
||||
}
|
||||
|
||||
public static double clamp(double input, double min, double max) {
|
||||
return Math.max(Math.min(input, max), min);
|
||||
}
|
||||
|
||||
public static long nextMidnight(long currentTime) {
|
||||
Date date = new Date();
|
||||
Calendar cal = Calendar.getInstance();
|
||||
|
||||
date.setTime(currentTime);
|
||||
cal.setTime(date);
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
cal.add(Calendar.HOUR_OF_DAY, 24);
|
||||
|
||||
return cal.getTime().getTime();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package core.api
|
||||
|
||||
import core.game.node.item.Item
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
fun IntRange.toIntArray(): IntArray {
|
||||
if (last < first)
|
||||
return IntArray(0)
|
||||
|
||||
val result = IntArray(last - first + 1)
|
||||
var index = 0
|
||||
for (element in this)
|
||||
result[index++] = element
|
||||
return result
|
||||
}
|
||||
|
||||
fun Int.asItem() : Item {
|
||||
return Item(this)
|
||||
}
|
||||
|
||||
fun Collection<IntArray>.toIntArray() : IntArray {
|
||||
val list = ArrayList<Int>()
|
||||
this.forEach { arr -> arr.forEach { list.add(it) } }
|
||||
return list.toIntArray()
|
||||
}
|
||||
|
||||
inline fun <reified T> Collection<T>.isLast(element: T) : Boolean {
|
||||
return this.indexOf(element) == this.size - 1
|
||||
}
|
||||
|
||||
inline fun <reified T> Collection<T>.getNext(element: T) : T {
|
||||
val idx = this.indexOf(element)
|
||||
return if (idx < this.size - 1)
|
||||
this.elementAt(idx + 1)
|
||||
else
|
||||
element
|
||||
}
|
||||
|
||||
inline fun <reified T> Collection<T>.isNextLast(element: T) : Boolean {
|
||||
return this.isLast(this.getNext(element))
|
||||
}
|
||||
|
||||
fun IntArray.isLast(element: Int) : Boolean {
|
||||
return this.indexOf(element) == this.size - 1
|
||||
}
|
||||
|
||||
fun IntArray.getNext(element: Int) : Int {
|
||||
val idx = this.indexOf(element)
|
||||
return if (idx < this.size - 1)
|
||||
this.elementAt(idx + 1)
|
||||
else
|
||||
element
|
||||
}
|
||||
|
||||
fun IntArray.isNextLast(element: Int) : Boolean {
|
||||
return this.isLast(this.getNext(element))
|
||||
}
|
||||
|
||||
fun <T> LinkedList<T>.tryPop(default: T) : T {
|
||||
this.peek() ?: return default
|
||||
return this.pop()
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package core.api
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.command.Command
|
||||
import core.game.system.command.CommandMapping
|
||||
import core.game.system.command.Privilege
|
||||
import core.tools.colorize
|
||||
|
||||
/**
|
||||
* An interface for writing content that allows the class to define commands.
|
||||
*
|
||||
* Includes methods [reject] and [notify] for notifying the player of a command rejection or some output text respectively.
|
||||
*
|
||||
* Includes the method [define] to define individual commands
|
||||
*
|
||||
* Commands should ideally be defined in the required [defineCommands] method.
|
||||
*/
|
||||
interface Commands : ContentInterface {
|
||||
/**
|
||||
* Glorified player.sendMessage with red text coloring. Please use this
|
||||
* rather than just player.sendMessage for anything that involves informing the player
|
||||
* of proper usage or invalid syntax. Throws an IllegalStateException and ends command execution immediately.
|
||||
*/
|
||||
fun reject(player: Player, vararg message: String){
|
||||
for(msg in message) {
|
||||
player.sendMessage(colorize("-->%R$msg"))
|
||||
}
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
/**
|
||||
* Glorified player.sendMessage with black text coloring and an arrow. Use this when you need to
|
||||
* notify/inform a player of some information from within the command without ending execution.
|
||||
*/
|
||||
fun notify(player: Player, message: String){
|
||||
player.sendMessage(colorize("-->$message"))
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to define commands. define("name",(optional) privilege override){ handle }
|
||||
* @param name the name of the command. Example: ::example would be just "example"
|
||||
* @param privilege the rights level needed to execute the command. Options are [Privilege.STANDARD], [Privilege.MODERATOR], [Privilege.ADMIN]. Defaults to [Privilege.STANDARD]
|
||||
*/
|
||||
fun define(name: String, privilege: Privilege = Privilege.ADMIN, usage: String = "", description: String = "", handle: (Player, Array<String>) -> Unit){
|
||||
CommandMapping.register(Command(name, privilege, usage, description, handle))
|
||||
}
|
||||
|
||||
fun defineCommands()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package core.api
|
||||
|
||||
enum class Container {
|
||||
INVENTORY,
|
||||
BANK,
|
||||
EQUIPMENT
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
package core.api
|
||||
|
||||
interface ContentInterface {
|
||||
/**
|
||||
* A dummy/shell interface that allows us to more easily load content via class scanning
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package core.api
|
||||
import java.util.*
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* Automatically split a single continuous string into multiple comma-separated lines.
|
||||
* Should this not work out for any reason, you should fallback to standard npc and player methods for dialogue.
|
||||
*/
|
||||
fun splitLines(message: String, perLineLimit: Int = 54) : Array<String> {
|
||||
var lines = Array(ceil(message.length / perLineLimit.toFloat()).toInt()) {""}
|
||||
|
||||
//short circuit when possible because it's cheaper.
|
||||
if (lines.size == 1) {
|
||||
lines[0] = message
|
||||
return lines
|
||||
}
|
||||
|
||||
val tokenQueue = LinkedList(message.split(" "))
|
||||
var index = 0
|
||||
val line = StringBuilder()
|
||||
var accumulator = 0
|
||||
|
||||
fun pushLine() {
|
||||
if (line.isEmpty()) return
|
||||
//allow array to be resized - there are specific edgecases where it becomes necessary. (Check the unit test for example)
|
||||
if (lines.size == index)
|
||||
lines = lines.plus(line.toString())
|
||||
else
|
||||
lines[index] = line.toString()
|
||||
index++
|
||||
line.clear()
|
||||
accumulator = 0
|
||||
}
|
||||
|
||||
while (!tokenQueue.isEmpty()) {
|
||||
val shouldSpace = line.isNotEmpty()
|
||||
accumulator += tokenQueue.peek().length
|
||||
|
||||
if (shouldSpace) accumulator += 1
|
||||
if (accumulator > perLineLimit) {
|
||||
pushLine()
|
||||
continue
|
||||
}
|
||||
|
||||
if (shouldSpace) line.append(" ")
|
||||
line.append(tokenQueue.pop())
|
||||
}
|
||||
|
||||
pushLine()
|
||||
return lines
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package core.api
|
||||
|
||||
enum class EquipmentSlot {
|
||||
HAT,
|
||||
CAPE,
|
||||
AMULET,
|
||||
WEAPON,
|
||||
CHEST,
|
||||
SHIELD,
|
||||
HIDDEN_1,
|
||||
LEGS,
|
||||
HIDDEN_2,
|
||||
HANDS,
|
||||
FEET,
|
||||
HIDDEN_3,
|
||||
RING,
|
||||
AMMO
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package core.api
|
||||
|
||||
import core.game.event.*
|
||||
|
||||
object Event {
|
||||
@JvmStatic val ResourceProduced = ResourceProducedEvent::class.java
|
||||
@JvmStatic val NPCKilled = NPCKillEvent::class.java
|
||||
@JvmStatic val Teleported = TeleportEvent::class.java
|
||||
@JvmStatic val FireLit = LitFireEvent::class.java
|
||||
@JvmStatic val Interacted = InteractionEvent::class.java
|
||||
@JvmStatic val ButtonClicked = ButtonClickEvent::class.java
|
||||
@JvmStatic val DialogueOpened = DialogueOpenEvent::class.java
|
||||
@JvmStatic val DialogueOptionSelected = DialogueOptionSelectionEvent::class.java
|
||||
@JvmStatic val DialogueClosed = DialogueCloseEvent::class.java
|
||||
@JvmStatic val UsedWith = UseWithEvent::class.java
|
||||
@JvmStatic val SelfDeath = SelfDeathEvent::class.java
|
||||
@JvmStatic val Tick = TickEvent::class.java
|
||||
@JvmStatic val PickedUp = PickUpEvent::class.java
|
||||
@JvmStatic val InterfaceOpened = InterfaceOpenEvent::class.java
|
||||
@JvmStatic val InterfaceClosed = InterfaceCloseEvent::class.java
|
||||
@JvmStatic val AttributeSet = AttributeSetEvent::class.java
|
||||
@JvmStatic val AttributeRemoved = AttributeRemoveEvent::class.java
|
||||
@JvmStatic val SpellCast = SpellCastEvent::class.java
|
||||
@JvmStatic val ItemAlchemized = ItemAlchemizationEvent::class.java
|
||||
@JvmStatic val ItemEquipped = ItemEquipEvent::class.java
|
||||
@JvmStatic val ItemUnequipped = ItemUnequipEvent::class.java
|
||||
@JvmStatic val ItemPurchased = ItemShopPurchaseEvent::class.java
|
||||
@JvmStatic val ItemSold = ItemShopSellEvent::class.java
|
||||
@JvmStatic val JobAssigned = JobAssignmentEvent::class.java
|
||||
@JvmStatic val FairyRingDialed = FairyRingDialEvent::class.java
|
||||
@JvmStatic val VarbitUpdated = VarbitUpdateEvent::class.java
|
||||
@JvmStatic val DynamicSkillLevelChanged = DynamicSkillLevelChangeEvent::class.java
|
||||
@JvmStatic val SummoningPointsRecharged = SummoningPointsRechargeEvent::class.java
|
||||
@JvmStatic val PrayerPointsRecharged = PrayerPointsRechargeEvent::class.java
|
||||
@JvmStatic val XpGained = XPGainEvent::class.java
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package core.api
|
||||
|
||||
enum class God(vararg val validItems: Int) {
|
||||
ARMADYL(87, 11694, 11718, 11720, 11722, 12670, 12671, 14671),
|
||||
BANDOS(11061, 11696, 11724, 11726, 11728),
|
||||
SARADOMIN(1718, 2412, 2415, 2661, 2663, 2665, 2667, 3479, 3675, 3489, 3840, 4682, 6762, 8055, 10384, 10386, 10388, 10390, 10440, 10446, 10452, 10458, 10464, 10470, 11181, 11698, 11730,542,544),
|
||||
ZAMORAK(11716, 11700, 1724, 2414, 2417, 2653, 2655, 2657, 2659, 3478, 3674, 3841, 3842, 3852, 4683, 6764, 8056, 10368, 10370, 10372, 10374, 10444, 10450, 10456, 10460, 10468, 10474, 10776, 10786, 10790, 14662),
|
||||
GUTHIX,
|
||||
ZAROS
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package core.api
|
||||
|
||||
/**
|
||||
* Used to generate interface settings hashes.
|
||||
* Deprecates [core.game.container.access.BitregisterAssembler]
|
||||
* @author Ceikry
|
||||
*/
|
||||
class IfaceSettingsBuilder {
|
||||
/**
|
||||
* Contains the value which should be sent in access mask packet.
|
||||
*/
|
||||
private var value = 0
|
||||
|
||||
/**
|
||||
* Sets right click option settings. If specified option is not allowed, it
|
||||
* might not appear in the context menu, and if it does, it will throw an error when clicked.
|
||||
* @param optionId The option index.
|
||||
*/
|
||||
fun enableOption(optionId: Int): IfaceSettingsBuilder {
|
||||
require(!(optionId < 0 || optionId > 9)) { "Option index must be 0-9." }
|
||||
value = value or (0x1 shl optionId + 1)
|
||||
return this
|
||||
}
|
||||
|
||||
fun enableOptions(vararg ids: Int): IfaceSettingsBuilder {
|
||||
for (i in ids.indices) {
|
||||
enableOption(ids[i])
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun enableOptions(ids: IntRange): IfaceSettingsBuilder {
|
||||
for (i in ids.start..ids.endInclusive) {
|
||||
enableOption(i)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun enableAllOptions(): IfaceSettingsBuilder {
|
||||
for (i in 0..9) {
|
||||
enableOption(i)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun enableOptions(vararg options: String?): IfaceSettingsBuilder {
|
||||
for (i in options.indices) {
|
||||
enableOption(i)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets use on option settings. If nothing is allowed then 'use' option will
|
||||
* not appear in right click menu.
|
||||
*/
|
||||
fun setUseOnSettings(
|
||||
groundItems: Boolean,
|
||||
npcs: Boolean,
|
||||
objects: Boolean,
|
||||
otherPlayer: Boolean,
|
||||
selfPlayer: Boolean,
|
||||
component: Boolean
|
||||
): IfaceSettingsBuilder {
|
||||
var useFlag = 0
|
||||
if (groundItems) {
|
||||
useFlag = useFlag or 0x1
|
||||
}
|
||||
if (npcs) {
|
||||
useFlag = useFlag or 0x2
|
||||
}
|
||||
if (objects) {
|
||||
useFlag = useFlag or 0x4
|
||||
}
|
||||
if (otherPlayer) {
|
||||
useFlag = useFlag or 0x8
|
||||
}
|
||||
if (selfPlayer) {
|
||||
useFlag = useFlag or 0x10
|
||||
}
|
||||
if (component) {
|
||||
useFlag = useFlag or 0x20
|
||||
}
|
||||
value = value or (useFlag shl 11)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets interface events depth. For example, we have inventory interface
|
||||
* which is opened on gameframe interface (548) If depth is 1, then the
|
||||
* clicks in inventory will also invoke click event handler scripts on
|
||||
* gameframe interface. Setting depth to 2 also allows dragged items to
|
||||
* leave the bounds of their container, useful for things such as bank tabs.
|
||||
* @param depth The depth value.
|
||||
*/
|
||||
fun setInterfaceEventsDepth(depth: Int): IfaceSettingsBuilder {
|
||||
require(!(depth < 0 || depth > 7)) { "depth must be 0-7." }
|
||||
value = value and (0x7 shl 18).inv()
|
||||
value = value or (depth shl 18)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows items in this interface container to be switched around
|
||||
* @return this builder
|
||||
*/
|
||||
fun enableSlotSwitch(): IfaceSettingsBuilder {
|
||||
value = value or (1 shl 21)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows items in this interface container to have a "Use" option
|
||||
* @return this builder
|
||||
*/
|
||||
fun enableUseOption(): IfaceSettingsBuilder {
|
||||
value = value or (1 shl 17)
|
||||
return this
|
||||
}
|
||||
|
||||
fun enableExamine(): IfaceSettingsBuilder {
|
||||
value = value or (1 shl 9)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows this component to have items used on it
|
||||
* @return this builder
|
||||
*/
|
||||
fun enableUseOnSelf(): IfaceSettingsBuilder {
|
||||
value = value or (1 shl 22)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows this component to switch item slots with a slot that contains a null (empty slot)
|
||||
* @return this builder
|
||||
*/
|
||||
fun enableNullSlotSwitch(): IfaceSettingsBuilder {
|
||||
value = value or (1 shl 23)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current value.
|
||||
* @return The value.
|
||||
*/
|
||||
fun build(): Int {
|
||||
return value
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package core.api
|
||||
|
||||
enum class InputType {
|
||||
AMOUNT,
|
||||
NUMERIC,
|
||||
STRING_SHORT,
|
||||
STRING_LONG,
|
||||
MESSAGE
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package core.api
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
|
||||
/**
|
||||
* An interface for writing content that allows the class to execute some code when a player logs in.
|
||||
*
|
||||
* Login listeners are called *before* [PersistPlayer] data is parsed.
|
||||
*/
|
||||
interface LoginListener : ContentInterface {
|
||||
/**
|
||||
* NOTE: This should NOT reference any non-static class-local variables.
|
||||
* If you need to access a player's specific instance, use an attribute.
|
||||
* Alternatively, consider using an [api.events.EventHook] if applicable.
|
||||
*/
|
||||
fun login(player: Player)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package core.api
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
|
||||
/**
|
||||
* An interface for writing content that allows code to be executed by the class when a player logs out.
|
||||
*
|
||||
* Logout listeners are called *before* [PersistPlayer] data is saved.
|
||||
*/
|
||||
interface LogoutListener : ContentInterface {
|
||||
/**
|
||||
* NOTE: This should NOT reference any non-static class-local variables.
|
||||
* If you need to access a player's specific instance, use an attribute.
|
||||
*/
|
||||
fun logout(player: Player)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package core.api
|
||||
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.zone.MapZone
|
||||
import core.game.world.map.zone.RegionZone
|
||||
import core.game.world.map.zone.ZoneBorders
|
||||
import core.game.world.map.zone.ZoneRestriction
|
||||
|
||||
/**
|
||||
* Interface that allows a class to define a map area.
|
||||
* Optionally-overridable methods include [getRestrictions], [areaEnter], [areaLeave] and [entityStep]
|
||||
*/
|
||||
interface MapArea : ContentInterface {
|
||||
var zone: MapZone
|
||||
get(){
|
||||
return zoneMaps[this.javaClass.simpleName + "MapArea"]!!
|
||||
}
|
||||
set(value) {
|
||||
zoneMaps[this.javaClass.simpleName + "MapArea"] = value
|
||||
}
|
||||
|
||||
fun defineAreaBorders() : Array<ZoneBorders>
|
||||
fun getRestrictions() : Array<ZoneRestriction> {return arrayOf()}
|
||||
fun areaEnter(entity: Entity) {}
|
||||
fun areaLeave(entity: Entity, logout: Boolean) {}
|
||||
fun entityStep(entity: Entity, location: Location, lastLocation: Location) {}
|
||||
|
||||
companion object {
|
||||
val zoneMaps = HashMap<String, MapZone>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package core.api
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import org.json.simple.JSONObject
|
||||
|
||||
/**
|
||||
* An interface for writing content that allows data to be saved and loaded from player saves.
|
||||
*
|
||||
* Parsing is called *after* any [LoginListener] is executed.
|
||||
*
|
||||
* Saving is called *after* any [LogoutListener] is executed.
|
||||
*/
|
||||
interface PersistPlayer : ContentInterface {
|
||||
/**
|
||||
* NOTE: This should NOT reference nonstatic class-local variables.
|
||||
* You need to fetch a player's specific instance of the data and save from that.
|
||||
* For reference, see [rs09.game.node.entity.skill.slayer.SlayerManager]
|
||||
*/
|
||||
fun savePlayer(player: Player, save: JSONObject)
|
||||
/**
|
||||
* NOTE: This should NOT reference nonstatic class-local variables.
|
||||
* You need to fetch a player's specific instance of the data and parse to that.
|
||||
* For reference, see [rs09.game.node.entity.skill.slayer.SlayerManager]
|
||||
*/
|
||||
fun parsePlayer(player: Player, data: JSONObject)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package core.api
|
||||
|
||||
interface PersistWorld : ContentInterface {
|
||||
fun save()
|
||||
fun parse()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package core.api
|
||||
|
||||
/**
|
||||
* An interface for writing content that allows the class to execute code as the server is shutting down
|
||||
*/
|
||||
interface ShutdownListener : ContentInterface {
|
||||
/**
|
||||
* NOTE: This should NOT reference nonstatic class-local variables.
|
||||
*/
|
||||
fun shutdown()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package core.api
|
||||
|
||||
/**
|
||||
* An interface for writing content that allows the class to execute code when the server is started.
|
||||
*/
|
||||
interface StartupListener : ContentInterface {
|
||||
/**
|
||||
* NOTE: This should NOT reference nonstatic class-local variables.
|
||||
*/
|
||||
fun startup()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package core.api
|
||||
|
||||
/**
|
||||
* An interface for writing content that allows the class to be updated each tick.
|
||||
*/
|
||||
interface TickListener : ContentInterface {
|
||||
/**
|
||||
* NOTE: This should NOT reference nonstatic class-local variables.
|
||||
* TickListeners are generally for NON-player, WORLD tick events.
|
||||
* Examples: Fishing spot rotation, grand exchange updates, puro puro randomization, etc.
|
||||
* If you need something (player/entity)-specific, use an [api.events.EventHook] with the [api.events.TickEvent]
|
||||
*/
|
||||
fun tick()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package core.api.regionspec
|
||||
|
||||
import core.api.regionspec.contracts.*
|
||||
import core.game.world.map.Region
|
||||
import core.game.world.map.RegionChunk
|
||||
import core.game.world.map.RegionPlane
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
|
||||
class RegionSpecification(val regionContract: RegionSpecContract = EmptyRegionContract(), vararg val chunkContracts: ChunkSpecContract = arrayOf(EmptyChunkContract())) {
|
||||
constructor(vararg chunkContracts: ChunkSpecContract) : this(EmptyRegionContract(), *chunkContracts)
|
||||
|
||||
fun build(): DynamicRegion {
|
||||
val dyn = regionContract.instantiateRegion()
|
||||
Region.load(dyn)
|
||||
chunkContracts.forEach { it.populateChunks(dyn) }
|
||||
return dyn
|
||||
}
|
||||
}
|
||||
|
||||
fun fillWith(chunk: RegionChunk?): FillChunkContract {
|
||||
return FillChunkContract(chunk)
|
||||
}
|
||||
|
||||
fun fillWith(delegate: (Int, Int, Int, Region) -> RegionChunk?) : FillChunkContract {
|
||||
return FillChunkContract(delegate)
|
||||
}
|
||||
|
||||
fun copyOf(regionId: Int): RegionSpecContract {
|
||||
return CloneRegionContract(regionId)
|
||||
}
|
||||
|
||||
fun using(region: DynamicRegion) : UseExistingRegionContract {
|
||||
return UseExistingRegionContract(region)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package core.api.regionspec.contracts
|
||||
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
|
||||
interface ChunkSpecContract {
|
||||
fun populateChunks(dyn: DynamicRegion)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package core.api.regionspec.contracts
|
||||
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
|
||||
class CloneRegionContract(val regionId: Int) : RegionSpecContract {
|
||||
override fun instantiateRegion(): DynamicRegion {
|
||||
return DynamicRegion.create(regionId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package core.api.regionspec.contracts
|
||||
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
|
||||
class EmptyChunkContract : ChunkSpecContract {
|
||||
override fun populateChunks(dyn: DynamicRegion) {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package core.api.regionspec.contracts
|
||||
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
|
||||
class EmptyRegionContract : RegionSpecContract {
|
||||
override fun instantiateRegion(): DynamicRegion {
|
||||
val borders = DynamicRegion.reserveArea(8,8)
|
||||
val dyn = DynamicRegion(borders)
|
||||
return dyn
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package core.api.regionspec.contracts
|
||||
|
||||
import core.game.world.map.BuildRegionChunk
|
||||
import core.game.world.map.Region
|
||||
import core.game.world.map.RegionChunk
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
|
||||
open class FillChunkContract(var chunk: RegionChunk? = null) : ChunkSpecContract {
|
||||
constructor(chunk: (Int, Int, Int, Region) -> RegionChunk?) : this(null) {this.chunkDelegate = chunk}
|
||||
|
||||
lateinit var sourceRegion: Region
|
||||
var planes: IntArray = intArrayOf(0)
|
||||
var replaceCondition: (Int,Int,Int) -> Boolean = {_,_,_ -> true}
|
||||
var chunkDelegate: (Int, Int, Int, Region) -> RegionChunk? = {_,_,_,_ -> chunk}
|
||||
|
||||
override fun populateChunks(dyn: DynamicRegion) {
|
||||
for(plane in planes) {
|
||||
for(x in 0 until 8)
|
||||
for(y in 0 until 8)
|
||||
if(replaceCondition.invoke(x,y,plane)) {
|
||||
val chunk = getChunk(x,y,plane,dyn)
|
||||
dyn.replaceChunk(
|
||||
plane,
|
||||
x,
|
||||
y,
|
||||
chunk,
|
||||
sourceRegion
|
||||
)
|
||||
afterSetting(chunk, x, y, plane, dyn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun getChunk(x: Int, y: Int, plane: Int, dyn: DynamicRegion) : BuildRegionChunk? {
|
||||
return chunkDelegate.invoke(x, y, plane, sourceRegion)?.copy(dyn.planes[plane])
|
||||
}
|
||||
|
||||
open fun afterSetting(chunk: BuildRegionChunk?, x: Int, y: Int, plane: Int, dyn: DynamicRegion) {}
|
||||
|
||||
fun from(region: Region): FillChunkContract {
|
||||
this.sourceRegion = region
|
||||
return this
|
||||
}
|
||||
|
||||
fun onPlanes(vararg planes: Int) : FillChunkContract {
|
||||
this.planes = planes
|
||||
return this
|
||||
}
|
||||
|
||||
fun onCondition(cond: (Int,Int,Int) -> Boolean): FillChunkContract {
|
||||
this.replaceCondition = cond
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package core.api.regionspec.contracts
|
||||
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
|
||||
interface RegionSpecContract {
|
||||
fun instantiateRegion(): DynamicRegion
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package core.api.regionspec.contracts
|
||||
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
|
||||
class UseExistingRegionContract(val region: DynamicRegion) : RegionSpecContract {
|
||||
override fun instantiateRegion(): DynamicRegion {
|
||||
return region;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package core.api.utils
|
||||
|
||||
object CameraUtils {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package core.api.utils
|
||||
|
||||
import core.api.ShutdownListener
|
||||
import core.api.StartupListener
|
||||
import core.game.node.entity.player.Player
|
||||
import core.tools.SystemLogger
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import org.json.simple.JSONObject
|
||||
import org.json.simple.parser.JSONParser
|
||||
import core.ServerConstants
|
||||
import core.game.node.item.Item
|
||||
import core.tools.SystemLogger.logShutdown
|
||||
import core.tools.SystemLogger.logStartup
|
||||
|
||||
class GlobalKillCounter : StartupListener, ShutdownListener {
|
||||
override fun startup() {
|
||||
logStartup("Parsing Global Kill Counts")
|
||||
val file = File(ServerConstants.DATA_PATH + File.separator + "global_kill_stats.json")
|
||||
if(!file.exists()) {
|
||||
return
|
||||
}
|
||||
|
||||
val reader = FileReader(file)
|
||||
val parser = JSONParser()
|
||||
try {
|
||||
val data = parser.parse(reader) as JSONObject
|
||||
val tmp_kills = data.get("kills")
|
||||
populate(kills, tmp_kills)
|
||||
val tmp_rare_drops = data.get("rare_drops")
|
||||
populate(rare_drops, tmp_rare_drops)
|
||||
} catch (e: Exception){
|
||||
SystemLogger.logErr(this::class.java, "Failed parsing ${file.name} - stack trace below.")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun shutdown() {
|
||||
logShutdown("Saving Global Kill Counts")
|
||||
val data = JSONObject()
|
||||
data.put("kills", saveField(kills))
|
||||
data.put("rare_drops", saveField(rare_drops))
|
||||
val file = File(ServerConstants.DATA_PATH + File.separator + "global_kill_stats.json")
|
||||
FileWriter(file).use { it.write(data.toJSONString()); it.flush(); it.close() }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val kills: HashMap<String, HashMap<Long, Long>> = HashMap()
|
||||
val rare_drops: HashMap<String, HashMap<Long, Long>> = HashMap()
|
||||
|
||||
@JvmStatic
|
||||
fun populate(field: HashMap<String, HashMap<Long, Long>>, obj: Any?) {
|
||||
if(obj != null && obj is JSONObject) {
|
||||
for((player, tmp_kc) in obj.asIterable()) {
|
||||
if(player is String) {
|
||||
val kc: HashMap<Long, Long> = HashMap()
|
||||
for((npc_id, count) in (tmp_kc as JSONObject).asIterable()) {
|
||||
kc.put(java.lang.Long.parseLong(npc_id as String), count as Long)
|
||||
}
|
||||
field.put(player, kc)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun saveField(field: HashMap<String, HashMap<Long, Long>>): JSONObject {
|
||||
val tmp_kills = JSONObject()
|
||||
for((player, kc) in field.asIterable()) {
|
||||
val tmp_kc = JSONObject()
|
||||
for((id, count) in kc.asIterable()) {
|
||||
tmp_kc.put(id, count)
|
||||
}
|
||||
tmp_kills.put(player, tmp_kc)
|
||||
}
|
||||
return tmp_kills
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun save() {
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun incrementKills(player: Player, npc_id: Int) {
|
||||
val player_kills = kills.getOrPut(player.username, { HashMap() })
|
||||
val old_amount = player_kills.getOrElse(npc_id.toLong(), { 0 })
|
||||
player_kills.put(npc_id.toLong(), 1 + old_amount)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun incrementRareDrop(player: Player, item: Item) {
|
||||
val player_drops = rare_drops.getOrPut(player.username, { HashMap() })
|
||||
val old_amount = player_drops.getOrElse(item.id.toLong(), { 0 })
|
||||
player_drops.put(item.id.toLong(), item.amount + old_amount)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getKills(player: Player, npc_id: Int): Long {
|
||||
return kills.getOrElse(player.username, { HashMap() }).getOrElse(npc_id.toLong(), { 0 })
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getKills(player: Player, npc_ids: IntArray): Long {
|
||||
var sum: Long = 0
|
||||
for(npc_id in npc_ids) {
|
||||
sum += getKills(player, npc_id)
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getRareDrops(player: Player, item_id: Int): Long {
|
||||
return rare_drops.getOrElse(player.username, { HashMap() }).getOrElse(item_id.toLong(), { 0 })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package core.api.utils
|
||||
|
||||
import core.game.node.item.Item
|
||||
|
||||
class NPCDropTable : WeightBasedTable() {
|
||||
private val charmDrops = WeightBasedTable()
|
||||
|
||||
fun addToCharms(element: WeightedItem): Boolean {
|
||||
return charmDrops.add(element)
|
||||
}
|
||||
|
||||
override fun roll(): ArrayList<Item> {
|
||||
val items = ArrayList<Item>()
|
||||
// Charms table is always rolled, and should contain explicit "Nothing"
|
||||
// entries at the data level to account for the chance to not drop a charm.
|
||||
items.addAll(charmDrops.roll())
|
||||
items.addAll(super.roll())
|
||||
return items
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package core.api.utils
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.net.packet.PacketRepository
|
||||
import core.net.packet.context.CameraContext
|
||||
import core.net.packet.out.CameraViewPacket
|
||||
|
||||
class PlayerCamera(val player: Player?) {
|
||||
var ctx: CameraContext? = null
|
||||
|
||||
fun setPosition(x: Int, y: Int, height: Int){
|
||||
player ?: return
|
||||
ctx = CameraContext(player,CameraContext.CameraType.SET,x,y,height,0,0)
|
||||
PacketRepository.send(CameraViewPacket::class.java,ctx)
|
||||
}
|
||||
fun rotateTo(x: Int, y: Int, height: Int, speed: Int){
|
||||
player ?: return
|
||||
ctx = CameraContext(player,CameraContext.CameraType.ROTATION,x,y,height,speed,1)
|
||||
PacketRepository.send(CameraViewPacket::class.java,ctx)
|
||||
}
|
||||
fun rotateBy(diffX: Int, diffY: Int, diffHeight: Int, speed: Int){
|
||||
player ?: return
|
||||
ctx ?: return
|
||||
ctx = CameraContext(player,CameraContext.CameraType.ROTATION, ctx!!.x + diffX, ctx!!.y + diffY, ctx!!.height + diffHeight,speed,1)
|
||||
PacketRepository.send(CameraViewPacket::class.java,ctx)
|
||||
}
|
||||
fun panTo(x: Int, y: Int, height: Int, speed: Int){
|
||||
player ?: return
|
||||
ctx = CameraContext(player,CameraContext.CameraType.POSITION,x,y,height,speed,1)
|
||||
PacketRepository.send(CameraViewPacket::class.java,ctx)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package core.api.utils
|
||||
|
||||
import core.cache.def.impl.ItemDefinition
|
||||
import content.global.activity.ttrail.ClueLevel
|
||||
import content.global.activity.ttrail.ClueScrollPlugin
|
||||
import content.data.tables.RareDropTable
|
||||
import content.data.tables.CELEMinorTable
|
||||
import content.data.tables.UncommonSeedDropTable
|
||||
import content.data.tables.HerbDropTable
|
||||
import content.data.tables.GemDropTable
|
||||
import content.data.tables.RareSeedDropTable
|
||||
import content.data.tables.AllotmentSeedDropTable
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.Item
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
|
||||
open class WeightBasedTable : ArrayList<WeightedItem>() {
|
||||
private var totalWeight = 0.0
|
||||
private val guaranteedItems = ArrayList<WeightedItem>()
|
||||
|
||||
override fun add(element: WeightedItem): Boolean {
|
||||
return if (element.guaranteed) {
|
||||
guaranteedItems.add(element)
|
||||
} else {
|
||||
totalWeight += element.weight
|
||||
super.add(element)
|
||||
}
|
||||
}
|
||||
|
||||
open fun roll(): ArrayList<Item>{
|
||||
val items = ArrayList<WeightedItem>()
|
||||
items.addAll(guaranteedItems)
|
||||
|
||||
if (size == 1) {
|
||||
items.add(get(0))
|
||||
}
|
||||
else if (isNotEmpty()) {
|
||||
var rngWeight = RandomFunction.randomDouble(totalWeight)
|
||||
for (item in shuffled()) {
|
||||
rngWeight -= item.weight
|
||||
if (rngWeight <= 0) {
|
||||
items.add(item)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return convertWeightedItems(items)
|
||||
}
|
||||
|
||||
private fun convertWeightedItems(weightedItems: ArrayList<WeightedItem>): ArrayList<Item> {
|
||||
val safeItems = ArrayList<Item>(weightedItems.size)
|
||||
weightedItems.forEach { e ->
|
||||
val safeItem = when (e.id) {
|
||||
SLOT_CLUE_EASY -> ClueScrollPlugin.getClue(ClueLevel.EASY)
|
||||
SLOT_CLUE_MEDIUM -> ClueScrollPlugin.getClue(ClueLevel.MEDIUM)
|
||||
SLOT_CLUE_HARD -> ClueScrollPlugin.getClue(ClueLevel.HARD)
|
||||
SLOT_RDT -> RareDropTable.retrieve()
|
||||
SLOT_CELEDT -> CELEMinorTable.retrieve()
|
||||
SLOT_USDT -> UncommonSeedDropTable.retrieve()
|
||||
SLOT_HDT -> HerbDropTable.retrieve()
|
||||
SLOT_GDT -> GemDropTable.retrieve()
|
||||
SLOT_RSDT -> RareSeedDropTable.retrieve()
|
||||
SLOT_ASDT -> AllotmentSeedDropTable.retrieve()
|
||||
else -> e.getItem()
|
||||
}
|
||||
safeItems.add(safeItem)
|
||||
}
|
||||
return safeItems
|
||||
}
|
||||
|
||||
open fun canRoll(player: Player): Boolean{
|
||||
val guaranteed = guaranteedItems.map { it.getItem() }.toTypedArray()
|
||||
return (guaranteed.isNotEmpty() && player.inventory.hasSpaceFor(*guaranteed)) || !player.inventory.isFull
|
||||
}
|
||||
|
||||
fun insertEasyClue(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_CLUE_EASY,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertMediumClue(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_CLUE_MEDIUM,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertHardClue(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_CLUE_HARD,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertRDTRoll(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_RDT,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertCELEDTRoll(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_CELEDT,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertSEEDDTRoll(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_USDT,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertHERBDTRoll(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_HDT,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertGDTRoll(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_GDT,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertRSDTRoll(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_RSDT,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertASDTRoll(weight: Double): WeightBasedTable {
|
||||
this.add(WeightedItem(SLOT_ASDT,1,1,weight,false))
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(vararg items: WeightedItem): WeightBasedTable {
|
||||
val table = WeightBasedTable()
|
||||
items.forEach {
|
||||
table.add(it)
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val SLOT_RDT = Items.TINDERBOX_31
|
||||
val SLOT_CLUE_EASY = Items.TOOLKIT_1
|
||||
val SLOT_CLUE_MEDIUM = Items.ROTTEN_POTATO_5733
|
||||
val SLOT_CLUE_HARD = Items.GRANITE_LOBSTER_POUCH_12070
|
||||
val SLOT_CELEDT = Items.NULL_799
|
||||
val SLOT_USDT = Items.SACRED_CLAY_POUCH_CLASS_1_14422
|
||||
val SLOT_HDT = Items.SACRED_CLAY_POUCH_CLASS_2_14424
|
||||
val SLOT_GDT = Items.SACRED_CLAY_POUCH_CLASS_3_14426
|
||||
val SLOT_RSDT = Items.SACRED_CLAY_POUCH_CLASS_4_14428
|
||||
val SLOT_ASDT = Items.SACRED_CLAY_POUCH_CLASS_5_14430
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val builder = StringBuilder()
|
||||
for(item in this){
|
||||
builder.append("${ItemDefinition.forId(item.id).name} || Weight: ${item.weight} || MinAmt: ${item.minAmt} || maxAmt: ${item.maxAmt}")
|
||||
builder.appendLine()
|
||||
}
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package core.api.utils
|
||||
|
||||
import core.game.node.item.Item
|
||||
import core.tools.RandomFunction
|
||||
|
||||
class WeightedItem(var id: Int, var minAmt: Int, var maxAmt: Int, var weight: Double, var guaranteed: Boolean = false) {
|
||||
fun getItem(): Item {
|
||||
return Item(id,RandomFunction.random(minAmt,maxAmt))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package core.auth
|
||||
|
||||
import core.ServerConstants
|
||||
import core.storage.AccountStorageProvider
|
||||
import core.storage.InMemoryStorageProvider
|
||||
import core.storage.SQLStorageProvider
|
||||
|
||||
object Auth {
|
||||
lateinit var authenticator: AuthProvider<*>
|
||||
lateinit var storageProvider: AccountStorageProvider
|
||||
|
||||
fun configure() {
|
||||
storageProvider = if (ServerConstants.PERSIST_ACCOUNTS)
|
||||
SQLStorageProvider()
|
||||
else
|
||||
InMemoryStorageProvider()
|
||||
|
||||
authenticator = if (ServerConstants.USE_AUTH)
|
||||
ProductionAuthenticator().also { it.configureFor(storageProvider) }
|
||||
else
|
||||
DevelopmentAuthenticator().also { it.configureFor(storageProvider) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package core.auth
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.storage.AccountStorageProvider
|
||||
|
||||
abstract class AuthProvider<T: AccountStorageProvider> {
|
||||
lateinit var storageProvider: T
|
||||
|
||||
abstract fun configureFor(provider: T)
|
||||
|
||||
fun canCreateAccountWith(info: UserAccountInfo) : Boolean {
|
||||
return !storageProvider.checkUsernameTaken(info.username)
|
||||
}
|
||||
|
||||
abstract fun createAccountWith(info: UserAccountInfo) : Boolean
|
||||
|
||||
abstract fun checkLogin(username: String, password: String) : Pair<AuthResponse, UserAccountInfo?>
|
||||
|
||||
abstract fun checkPassword(player: Player, password: String) : Boolean
|
||||
|
||||
abstract fun updatePassword(username: String, newPassword: String)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package core.auth
|
||||
|
||||
enum class AuthResponse {
|
||||
UnexpectedError,
|
||||
CouldNotAd,
|
||||
Success,
|
||||
InvalidCredentials,
|
||||
AccountDisabled,
|
||||
AlreadyOnline,
|
||||
Updated,
|
||||
FullWorld,
|
||||
LoginServerOffline,
|
||||
LoginLimitExceeded,
|
||||
BadSessionID,
|
||||
WeakPassword,
|
||||
MembersWorld,
|
||||
CouldNotLogin,
|
||||
Updating,
|
||||
TooManyIncorrectLogins,
|
||||
StandingInMembersArea,
|
||||
AccountLocked,
|
||||
ClosedBeta,
|
||||
InvalidLoginServer,
|
||||
MovingWorld,
|
||||
ErrorLoadingProfile,
|
||||
BannedUser
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package core.auth
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.ServerConstants
|
||||
import core.storage.AccountStorageProvider
|
||||
|
||||
class DevelopmentAuthenticator : AuthProvider<AccountStorageProvider>() {
|
||||
override fun configureFor(provider: AccountStorageProvider) {
|
||||
storageProvider = provider
|
||||
}
|
||||
|
||||
override fun checkLogin(username: String, password: String): Pair<AuthResponse, UserAccountInfo?> {
|
||||
val info: UserAccountInfo
|
||||
if(!storageProvider.checkUsernameTaken(username.toLowerCase())) {
|
||||
info = UserAccountInfo.createDefault()
|
||||
info.username = username
|
||||
createAccountWith(info)
|
||||
} else {
|
||||
info = storageProvider.getAccountInfo(username.toLowerCase())
|
||||
}
|
||||
return Pair(AuthResponse.Success, storageProvider.getAccountInfo(username))
|
||||
}
|
||||
|
||||
override fun createAccountWith(info: UserAccountInfo): Boolean {
|
||||
info.username = info.username.toLowerCase()
|
||||
if (ServerConstants.NOAUTH_DEFAULT_ADMIN)
|
||||
info.rights = 2
|
||||
storageProvider.store(info)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun checkPassword(player: Player, password: String): Boolean {
|
||||
return password == player.details.password
|
||||
}
|
||||
|
||||
override fun updatePassword(username: String, newPassword: String) {
|
||||
val info = storageProvider.getAccountInfo(username)
|
||||
info.password = newPassword
|
||||
storageProvider.update(info)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package core.auth
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.SystemManager
|
||||
import core.ServerConstants
|
||||
import core.storage.AccountStorageProvider
|
||||
import core.storage.SQLStorageProvider
|
||||
import java.sql.SQLDataException
|
||||
import java.sql.Timestamp
|
||||
|
||||
class ProductionAuthenticator : AuthProvider<AccountStorageProvider>() {
|
||||
override fun configureFor(provider: AccountStorageProvider) {
|
||||
storageProvider = provider
|
||||
if (provider is SQLStorageProvider) {
|
||||
provider.configure(ServerConstants.DATABASE_ADDRESS!!, ServerConstants.DATABASE_NAME!!, ServerConstants.DATABASE_USER!!, ServerConstants.DATABASE_PASS!!)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createAccountWith(info: UserAccountInfo): Boolean {
|
||||
try {
|
||||
info.password = SystemManager.getEncryption().hashPassword(info.password)
|
||||
info.joinDate = Timestamp(System.currentTimeMillis())
|
||||
storageProvider.store(info)
|
||||
} catch (e: SQLDataException) {
|
||||
return false
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun checkLogin(username: String, password: String): Pair<AuthResponse, UserAccountInfo?> {
|
||||
val info: UserAccountInfo
|
||||
try {
|
||||
if (!storageProvider.checkUsernameTaken(username.toLowerCase())) {
|
||||
return Pair(AuthResponse.InvalidCredentials, null)
|
||||
}
|
||||
info = storageProvider.getAccountInfo(username.toLowerCase())
|
||||
val passCorrect = SystemManager.getEncryption().checkPassword(password, info.password)
|
||||
if(!passCorrect || info.password.isEmpty())
|
||||
return Pair(AuthResponse.InvalidCredentials, null)
|
||||
if(info.banEndTime > System.currentTimeMillis())
|
||||
return Pair(AuthResponse.AccountDisabled, null)
|
||||
if(info.online)
|
||||
return Pair(AuthResponse.AlreadyOnline, null)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return Pair(AuthResponse.CouldNotLogin, null)
|
||||
}
|
||||
return Pair(AuthResponse.Success, info)
|
||||
}
|
||||
|
||||
override fun checkPassword(player: Player, password: String): Boolean {
|
||||
return SystemManager.getEncryption().checkPassword(password, player.details.password)
|
||||
}
|
||||
|
||||
override fun updatePassword(username: String, newPassword: String) {
|
||||
val info = storageProvider.getAccountInfo(username)
|
||||
info.password = SystemManager.getEncryption().hashPassword(newPassword)
|
||||
storageProvider.update(info)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package core.auth
|
||||
|
||||
import java.sql.Timestamp
|
||||
|
||||
class UserAccountInfo(
|
||||
var username: String,
|
||||
var password: String,
|
||||
var uid: Int,
|
||||
var rights: Int,
|
||||
var credits: Int,
|
||||
var ip: String,
|
||||
var lastUsedIp: String,
|
||||
var muteEndTime: Long,
|
||||
var banEndTime: Long,
|
||||
var contacts: String,
|
||||
var blocked: String,
|
||||
var clanName: String,
|
||||
var currentClan: String,
|
||||
var clanReqs: String,
|
||||
var timePlayed: Long,
|
||||
var lastLogin: Long,
|
||||
var online: Boolean,
|
||||
var joinDate: Timestamp
|
||||
) {
|
||||
companion object {
|
||||
val default = createDefault()
|
||||
@JvmStatic fun createDefault() : UserAccountInfo {
|
||||
return UserAccountInfo("", "", 0, 0, 0, "", "", 0L, 0L, "", "", "", "", "1,0,8,9", 0L, 0L, false, joinDate = Timestamp(System.currentTimeMillis())).also { it.setInitialReferenceValues() }
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var initialValues: Array<Any>
|
||||
|
||||
fun setInitialReferenceValues() {
|
||||
initialValues = toArray()
|
||||
}
|
||||
|
||||
fun getChangedFields(): Pair<ArrayList<Int>, Array<Any>> {
|
||||
val current = toArray()
|
||||
val changed = ArrayList<Int>()
|
||||
|
||||
for(i in current.indices) {
|
||||
if (current[i] != initialValues[i]) changed.add(i)
|
||||
}
|
||||
|
||||
return Pair(changed, current)
|
||||
}
|
||||
|
||||
fun toArray(): Array<Any> {
|
||||
return arrayOf(username, password, uid, rights, credits, ip, lastUsedIp, muteEndTime, banEndTime, contacts, blocked, clanName, currentClan, clanReqs, timePlayed, lastLogin, online, joinDate)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "USER:$username,PASS:$password,UID:$uid,RIGHTS:$rights,CREDITS:$credits,IP:$ip,LASTIP:$lastUsedIp"
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as UserAccountInfo
|
||||
|
||||
if (username != other.username) return false
|
||||
if (password != other.password) return false
|
||||
if (uid != other.uid) return false
|
||||
if (rights != other.rights) return false
|
||||
if (credits != other.credits) return false
|
||||
if (ip != other.ip) return false
|
||||
if (lastUsedIp != other.lastUsedIp) return false
|
||||
if (muteEndTime != other.muteEndTime) return false
|
||||
if (banEndTime != other.banEndTime) return false
|
||||
if (contacts != other.contacts) return false
|
||||
if (blocked != other.blocked) return false
|
||||
if (clanName != other.clanName) return false
|
||||
if (currentClan != other.currentClan) return false
|
||||
if (clanReqs != other.clanReqs) return false
|
||||
if (timePlayed != other.timePlayed) return false
|
||||
if (lastLogin != other.lastLogin) return false
|
||||
if (online != other.online) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = username.hashCode()
|
||||
result = 31 * result + password.hashCode()
|
||||
result = 31 * result + uid
|
||||
result = 31 * result + rights
|
||||
result = 31 * result + credits
|
||||
result = 31 * result + ip.hashCode()
|
||||
result = 31 * result + lastUsedIp.hashCode()
|
||||
result = 31 * result + muteEndTime.hashCode()
|
||||
result = 31 * result + banEndTime.hashCode()
|
||||
result = 31 * result + contacts.hashCode()
|
||||
result = 31 * result + blocked.hashCode()
|
||||
result = 31 * result + clanName.hashCode()
|
||||
result = 31 * result + currentClan.hashCode()
|
||||
result = 31 * result + clanReqs.hashCode()
|
||||
result = 31 * result + timePlayed.hashCode()
|
||||
result = 31 * result + lastLogin.hashCode()
|
||||
result = 31 * result + online.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
fun isDefault() : Boolean {
|
||||
return this == default
|
||||
}
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
package core.cache;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import core.ServerConstants;
|
||||
import core.cache.def.impl.AnimationDefinition;
|
||||
import core.cache.def.impl.GraphicDefinition;
|
||||
import core.cache.def.impl.ItemDefinition;
|
||||
import core.cache.def.impl.NPCDefinition;
|
||||
import core.cache.def.impl.SceneryDefinition;
|
||||
import core.tools.SystemLogger;
|
||||
|
||||
/**
|
||||
* A cache reader.
|
||||
*
|
||||
* @author Emperor
|
||||
* @author Dragonkk
|
||||
*/
|
||||
public final class Cache {
|
||||
|
||||
/**
|
||||
* The cache file manager.
|
||||
*/
|
||||
private static CacheFileManager[] cacheFileManagers;
|
||||
|
||||
/**
|
||||
* The container cache file informer.
|
||||
*/
|
||||
private static CacheFile referenceFile;
|
||||
|
||||
/**
|
||||
* Construct a new instance.
|
||||
*/
|
||||
private Cache(String location) {
|
||||
try {
|
||||
init(location);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the cache reader.
|
||||
*
|
||||
* @param path The cache path.x
|
||||
* @throws Throwable When an exception occurs.
|
||||
*/
|
||||
public static void init(String path) throws Throwable {
|
||||
SystemLogger.logInfo(Cache.class, "Initializing cache...");
|
||||
byte[] cacheFileBuffer = new byte[520];
|
||||
RandomAccessFile containersInformFile = new RandomAccessFile(path + File.separator + "main_file_cache.idx255", "r");
|
||||
RandomAccessFile dataFile = new RandomAccessFile(path + File.separator + "main_file_cache.dat2", "r");
|
||||
referenceFile = new CacheFile(255, containersInformFile, dataFile, 500000, cacheFileBuffer);
|
||||
int length = (int) (containersInformFile.length() / 6);
|
||||
cacheFileManagers = new CacheFileManager[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
File f = new File(path + File.separator + "main_file_cache.idx" + i);
|
||||
if (f.exists() && f.length() > 0) {
|
||||
CacheFile cacheFile = new CacheFile(i, new RandomAccessFile(f, "r"), dataFile, 1000000, cacheFileBuffer);
|
||||
cacheFileManagers[i] = new CacheFileManager(cacheFile, true);
|
||||
if (cacheFileManagers[i].getInformation() == null) {
|
||||
SystemLogger.logErr(Cache.class, "Error loading cache index " + i + ": no information.");
|
||||
cacheFileManagers[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemDefinition.parse();
|
||||
SceneryDefinition.parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the cache.
|
||||
*/
|
||||
public static void init() {
|
||||
try {
|
||||
init(ServerConstants.CACHE_PATH);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the archive buffer for the grab requests.
|
||||
*
|
||||
* @param index The index id.
|
||||
* @param archive The archive id.
|
||||
* @param priority The priority.
|
||||
* @param encryptionValue The current encryption value.
|
||||
* @return The byte buffer.
|
||||
*/
|
||||
public static ByteBuffer getArchiveData(int index, int archive, boolean priority, int encryptionValue) {
|
||||
byte[] data = index == 255 ? referenceFile.getContainerData(archive) : cacheFileManagers[index].getCacheFile().getContainerData(archive);
|
||||
if (data == null || data.length < 1) {
|
||||
SystemLogger.logErr(Cache.class, "Invalid JS-5 request - " + index + ", " + archive + ", " + priority + ", " + encryptionValue + "!");
|
||||
return null;
|
||||
}
|
||||
int compression = data[0] & 0xff;
|
||||
int length = ((data[1] & 0xff) << 24) + ((data[2] & 0xff) << 16) + ((data[3] & 0xff) << 8) + (data[4] & 0xff);
|
||||
int settings = compression;
|
||||
if (!priority) {
|
||||
settings |= 0x80;
|
||||
}
|
||||
int realLength = compression != 0 ? length + 4 : length;
|
||||
|
||||
// TODO There are two archives that lack two bytes at the end (The version, most likely). This causes the client CRC to be miscalculated. To combat this, we simply send two more bytes if the length seems to be off.
|
||||
realLength += (index != 255 && compression != 0 && data.length - length == 9) ? 2 : 0;
|
||||
ByteBuffer buffer = ByteBuffer.allocate((realLength + 5) + (realLength / 512) + 10);
|
||||
buffer.put((byte) index);
|
||||
buffer.putShort((short) archive);
|
||||
buffer.put((byte) settings);
|
||||
buffer.putInt(length);
|
||||
for (int i = 5; i < realLength + 5; i++) {
|
||||
if (buffer.position() % 512 == 0) {
|
||||
buffer.put((byte) 255);
|
||||
}
|
||||
if (data.length > i)
|
||||
buffer.put(data[i]);
|
||||
else
|
||||
buffer.put((byte) 0);
|
||||
}
|
||||
if (encryptionValue != 0) {
|
||||
for (int i = 0; i < buffer.position(); i++) {
|
||||
buffer.put(i, (byte) (buffer.get(i) ^ encryptionValue));
|
||||
}
|
||||
}
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the reference data for the cache files.
|
||||
*
|
||||
* @return The reference data byte array.
|
||||
*/
|
||||
public static final byte[] generateReferenceData() {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(cacheFileManagers.length * 8);
|
||||
for (int index = 0; index < cacheFileManagers.length; index++) {
|
||||
if (cacheFileManagers[index] == null) {
|
||||
buffer.putInt(index == 24 ? 609698396 : 0);
|
||||
buffer.putInt(0);
|
||||
continue;
|
||||
}
|
||||
buffer.putInt(cacheFileManagers[index].getInformation().getInformationContainer().getCrc());
|
||||
buffer.putInt(cacheFileManagers[index].getInformation().getRevision());
|
||||
}
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cache file managers.
|
||||
*
|
||||
* @return The cache file managers.
|
||||
*/
|
||||
public static final CacheFileManager[] getIndexes() {
|
||||
return cacheFileManagers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container cache file informer.
|
||||
*
|
||||
* @return The container cache file informer.
|
||||
*/
|
||||
public static final CacheFile getReferenceFile() {
|
||||
return referenceFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to return the component size of the interface.
|
||||
*
|
||||
* @param interfaceId the interface.
|
||||
* @return the value.
|
||||
*/
|
||||
public static final int getInterfaceDefinitionsComponentsSize(int interfaceId) {
|
||||
return getIndexes()[3].getFilesSize(interfaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to return the max size of the interface definitions.
|
||||
*
|
||||
* @return the size.
|
||||
*/
|
||||
public static final int getInterfaceDefinitionsSize() {
|
||||
return getIndexes()[3].getContainersSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to return the {@link NPCDefinition} size.
|
||||
*
|
||||
* @return the size.
|
||||
*/
|
||||
public static final int getNPCDefinitionsSize() {
|
||||
int lastContainerId = getIndexes()[18].getContainersSize() - 1;
|
||||
return lastContainerId * 128 + getIndexes()[18].getFilesSize(lastContainerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to return the {@link GraphicDefinition} size.
|
||||
*
|
||||
* @return the size.
|
||||
*/
|
||||
public static final int getGraphicDefinitionsSize() {
|
||||
int lastContainerId = getIndexes()[21].getContainersSize() - 1;
|
||||
return lastContainerId * 256 + getIndexes()[21].getFilesSize(lastContainerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to return the {@link AnimationDefinition} size.
|
||||
*
|
||||
* @return the size.
|
||||
*/
|
||||
public static final int getAnimationDefinitionsSize() {
|
||||
int lastContainerId = getIndexes()[20].getContainersSize() - 1;
|
||||
return lastContainerId * 128 + getIndexes()[20].getFilesSize(lastContainerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to return the {@link SceneryDefinition} size.
|
||||
*
|
||||
* @return the size.
|
||||
*/
|
||||
public static final int getObjectDefinitionsSize() {
|
||||
int lastContainerId = getIndexes()[16].getContainersSize() - 1;
|
||||
return lastContainerId * 256 + getIndexes()[16].getFilesSize(lastContainerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to return the item definition size.
|
||||
*
|
||||
* @return the size.
|
||||
*/
|
||||
public static final int getItemDefinitionsSize() {
|
||||
int lastContainerId = getIndexes()[19].getContainersSize() - 1;
|
||||
return lastContainerId * 256 + getIndexes()[19].getFilesSize(lastContainerId);
|
||||
}
|
||||
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package core.cache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import core.cache.crypto.XTEACryption;
|
||||
import core.cache.misc.ContainersInformation;
|
||||
|
||||
/**
|
||||
* A cache file.
|
||||
* @author Dragonkk
|
||||
*/
|
||||
public final class CacheFile {
|
||||
|
||||
/**
|
||||
* The index file id.
|
||||
*/
|
||||
private int indexFileId;
|
||||
|
||||
/**
|
||||
* The cache file buffer.
|
||||
*/
|
||||
private byte[] cacheFileBuffer;
|
||||
|
||||
/**
|
||||
* The maximum container size.
|
||||
*/
|
||||
private int maxContainerSize;
|
||||
|
||||
/**
|
||||
* The index file.
|
||||
*/
|
||||
private RandomAccessFile indexFile;
|
||||
|
||||
/**
|
||||
* The data file.
|
||||
*/
|
||||
private RandomAccessFile dataFile;
|
||||
|
||||
/**
|
||||
* Construct a new cache file.
|
||||
* @param indexFileId The index file id.
|
||||
* @param indexFile The index file.
|
||||
* @param dataFile The data file.
|
||||
* @param maxContainerSize The maximum container size.
|
||||
* @param cacheFileBuffer The cache file buffer.
|
||||
*/
|
||||
public CacheFile(int indexFileId, RandomAccessFile indexFile, RandomAccessFile dataFile, int maxContainerSize, byte[] cacheFileBuffer) {
|
||||
this.cacheFileBuffer = cacheFileBuffer;
|
||||
this.indexFileId = indexFileId;
|
||||
this.maxContainerSize = maxContainerSize;
|
||||
this.indexFile = indexFile;
|
||||
this.dataFile = dataFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unpacked container data.
|
||||
* @param containerId The container id.
|
||||
* @param xteaKeys The container keys.
|
||||
* @return The unpacked container data.
|
||||
*/
|
||||
public final byte[] getContainerUnpackedData(int containerId, int[] xteaKeys) {
|
||||
byte[] packedData = getContainerData(containerId);
|
||||
if (packedData == null) {
|
||||
return null;
|
||||
}
|
||||
if (xteaKeys != null && (xteaKeys[0] != 0 || xteaKeys[1] != 0 || xteaKeys[2] != 0 || xteaKeys[3] != 0)) {
|
||||
packedData = XTEACryption.decrypt(xteaKeys, ByteBuffer.wrap(packedData), 5, packedData.length).array();
|
||||
}
|
||||
return ContainersInformation.unpackCacheContainer(packedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container data for the specified container id.
|
||||
* @param containerId The container id.
|
||||
* @return The container data.
|
||||
*/
|
||||
public final byte[] getContainerData(int containerId) {
|
||||
synchronized (dataFile) {
|
||||
try {
|
||||
if (indexFile.length() < (6 * containerId + 6)) {
|
||||
return null;
|
||||
}
|
||||
indexFile.seek(6 * containerId);
|
||||
indexFile.read(cacheFileBuffer, 0, 6);
|
||||
int containerSize = (cacheFileBuffer[2] & 0xff) + (((0xff & cacheFileBuffer[0]) << 16) + (cacheFileBuffer[1] << 8 & 0xff00));
|
||||
int sector = ((cacheFileBuffer[3] & 0xff) << 16) - (-(0xff00 & cacheFileBuffer[4] << 8) - (cacheFileBuffer[5] & 0xff));
|
||||
if (containerSize < 0 || containerSize > maxContainerSize) {
|
||||
return null;
|
||||
}
|
||||
if (sector <= 0 || dataFile.length() / 520L < sector) {
|
||||
return null;
|
||||
}
|
||||
byte data[] = new byte[containerSize];
|
||||
int dataReadCount = 0;
|
||||
int part = 0;
|
||||
while (containerSize > dataReadCount) {
|
||||
if (sector == 0) {
|
||||
return null;
|
||||
}
|
||||
dataFile.seek(520 * sector);
|
||||
int dataToReadCount = containerSize - dataReadCount;
|
||||
if (dataToReadCount > 512) {
|
||||
dataToReadCount = 512;
|
||||
}
|
||||
dataFile.read(cacheFileBuffer, 0, 8 + dataToReadCount);
|
||||
int currentContainerId = (0xff & cacheFileBuffer[1]) + (0xff00 & cacheFileBuffer[0] << 8);
|
||||
int currentPart = ((cacheFileBuffer[2] & 0xff) << 8) + (0xff & cacheFileBuffer[3]);
|
||||
int nextSector = (cacheFileBuffer[6] & 0xff) + (0xff00 & cacheFileBuffer[5] << 8) + ((0xff & cacheFileBuffer[4]) << 16);
|
||||
int currentIndexFileId = cacheFileBuffer[7] & 0xff;
|
||||
if (containerId != currentContainerId || currentPart != part || indexFileId != currentIndexFileId) {
|
||||
return null;
|
||||
}
|
||||
if (nextSector < 0 || (dataFile.length() / 520L) < nextSector) {
|
||||
return null;
|
||||
}
|
||||
for (int index = 0; dataToReadCount > index; index++) {
|
||||
data[dataReadCount++] = cacheFileBuffer[8 + index];
|
||||
}
|
||||
part++;
|
||||
sector = nextSector;
|
||||
}
|
||||
return data;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index file id.
|
||||
* @return
|
||||
*/
|
||||
public int getIndexFileId() {
|
||||
return indexFileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unpacked container data.
|
||||
* @param containerId The container id.
|
||||
* @return The unpacked container data.
|
||||
*/
|
||||
public final byte[] getContainerUnpackedData(int containerId) {
|
||||
return getContainerUnpackedData(containerId, null);
|
||||
}
|
||||
}
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
package core.cache;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import core.cache.misc.ContainersInformation;
|
||||
import core.tools.StringUtils;
|
||||
|
||||
/**
|
||||
* A cache file manager.
|
||||
* @author Dragonkk
|
||||
*/
|
||||
public final class CacheFileManager {
|
||||
|
||||
/**
|
||||
* The cache file.
|
||||
*/
|
||||
private CacheFile cacheFile;
|
||||
|
||||
/**
|
||||
* The containers information.
|
||||
*/
|
||||
private ContainersInformation information;
|
||||
|
||||
/**
|
||||
* Discard a files data.
|
||||
*/
|
||||
private boolean discardFilesData;
|
||||
|
||||
/**
|
||||
* A array holding file data.
|
||||
*/
|
||||
private byte[][][] filesData;
|
||||
|
||||
/**
|
||||
* Construct a new cache file manager.
|
||||
* @param cacheFile The cache file.
|
||||
* @param discardFilesData To discard a files data.
|
||||
*/
|
||||
public CacheFileManager(CacheFile cacheFile, boolean discardFilesData) {
|
||||
this.cacheFile = cacheFile;
|
||||
this.discardFilesData = discardFilesData;
|
||||
byte[] informContainerPackedData = Cache.getReferenceFile().getContainerData(cacheFile.getIndexFileId());
|
||||
if (informContainerPackedData == null) {
|
||||
return;
|
||||
}
|
||||
information = new ContainersInformation(informContainerPackedData);
|
||||
resetFilesData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cache file.
|
||||
* @return The cache file.
|
||||
*/
|
||||
public CacheFile getCacheFile() {
|
||||
return cacheFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the containers size.
|
||||
* @return The containers size.
|
||||
*/
|
||||
public int getContainersSize() {
|
||||
return information.getContainers().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the files size.
|
||||
* @param containerId The container id.
|
||||
* @return The files size.
|
||||
*/
|
||||
public int getFilesSize(int containerId) {
|
||||
if (!validContainer(containerId)) {
|
||||
return -1;
|
||||
}
|
||||
return information.getContainers()[containerId].getFiles().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the file data.
|
||||
*/
|
||||
public void resetFilesData() {
|
||||
filesData = new byte[information.getContainers().length][][];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file is valid.
|
||||
* @param containerId The container id.
|
||||
* @param fileId The file id.
|
||||
* @return If the file is valid {@code true}.
|
||||
*/
|
||||
public boolean validFile(int containerId, int fileId) {
|
||||
if (!validContainer(containerId)) {
|
||||
return false;
|
||||
}
|
||||
if (fileId < 0 || information.getContainers()[containerId] == null || information.getContainers()[containerId].getFiles().length <= fileId) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* If a container is valid.
|
||||
* @param containerId The container id.
|
||||
* @return If the container is valid {@code true}.
|
||||
*/
|
||||
public boolean validContainer(int containerId) {
|
||||
if (containerId < 0 || information.getContainers().length <= containerId) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file ids.
|
||||
* @param containerId The container id.
|
||||
* @return The file ids.
|
||||
*/
|
||||
public int[] getFileIds(int containerId) {
|
||||
if (!validContainer(containerId)) {
|
||||
return null;
|
||||
}
|
||||
return information.getContainers()[containerId].getFilesIndexes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the archive id.
|
||||
* @param name The archive name.
|
||||
* @return The archive id.
|
||||
*/
|
||||
public int getArchiveId(String name) {
|
||||
if (name == null) {
|
||||
return -1;
|
||||
}
|
||||
int hash = StringUtils.getNameHash(name);
|
||||
for (int containerIndex = 0; containerIndex < information.getContainersIndexes().length; containerIndex++) {
|
||||
if (information.getContainers()[information.getContainersIndexes()[containerIndex]].getNameHash() == hash) {
|
||||
return information.getContainersIndexes()[containerIndex];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file data.
|
||||
* @param containerId The container id.
|
||||
* @param fileId The file id.
|
||||
* @return The get file data.
|
||||
*/
|
||||
public byte[] getFileData(int containerId, int fileId) {
|
||||
return getFileData(containerId, fileId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the file data.
|
||||
* @param archiveId The container id.
|
||||
* @param keys The container keys.
|
||||
* @return If the file data is loaded {@code true}.
|
||||
*/
|
||||
public boolean loadFilesData(int archiveId, int[] keys) {
|
||||
byte[] data = cacheFile.getContainerUnpackedData(archiveId, keys);
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
if (filesData[archiveId] == null) {
|
||||
if (information.getContainers()[archiveId] == null) {
|
||||
return false; // container inform doesnt exist anymore
|
||||
}
|
||||
filesData[archiveId] = new byte[information.getContainers()[archiveId].getFiles().length][];
|
||||
}
|
||||
if (information.getContainers()[archiveId].getFilesIndexes().length == 1) {
|
||||
int fileId = information.getContainers()[archiveId].getFilesIndexes()[0];
|
||||
filesData[archiveId][fileId] = data;
|
||||
} else {
|
||||
int readPosition = data.length;
|
||||
int amtOfLoops = data[--readPosition] & 0xff;
|
||||
readPosition -= amtOfLoops * (information.getContainers()[archiveId].getFilesIndexes().length * 4);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||
int filesSize[] = new int[information.getContainers()[archiveId].getFilesIndexes().length];
|
||||
buffer.position(readPosition);
|
||||
for (int loop = 0; loop < amtOfLoops; loop++) {
|
||||
int offset = 0;
|
||||
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
|
||||
filesSize[fileIndex] += offset += buffer.getInt();
|
||||
}
|
||||
}
|
||||
byte[][] filesBufferData = new byte[information.getContainers()[archiveId].getFilesIndexes().length][];
|
||||
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
|
||||
filesBufferData[fileIndex] = new byte[filesSize[fileIndex]];
|
||||
filesSize[fileIndex] = 0;
|
||||
}
|
||||
buffer.position(readPosition);
|
||||
int sourceOffset = 0;
|
||||
for (int loop = 0; loop < amtOfLoops; loop++) {
|
||||
int dataRead = 0;
|
||||
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
|
||||
dataRead += buffer.getInt();
|
||||
System.arraycopy(data, sourceOffset, filesBufferData[fileIndex], filesSize[fileIndex], dataRead);
|
||||
sourceOffset += dataRead;
|
||||
filesSize[fileIndex] += dataRead;
|
||||
}
|
||||
}
|
||||
for (int fileIndex = 0; fileIndex < information.getContainers()[archiveId].getFilesIndexes().length; fileIndex++) {
|
||||
filesData[archiveId][information.getContainers()[archiveId].getFilesIndexes()[fileIndex]] = filesBufferData[fileIndex];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file data.
|
||||
* @param containerId The container id.
|
||||
* @param fileId The file id.
|
||||
* @param xteaKeys The container keys.
|
||||
* @return The file data.
|
||||
*/
|
||||
public byte[] getFileData(int containerId, int fileId, int[] xteaKeys) {
|
||||
if (!validFile(containerId, fileId)) {
|
||||
return null;
|
||||
}
|
||||
if (filesData[containerId] == null || filesData[containerId][fileId] == null) {
|
||||
if (!loadFilesData(containerId, xteaKeys)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
byte[] data = filesData[containerId][fileId];
|
||||
if (discardFilesData) {
|
||||
if (filesData[containerId].length == 1) {
|
||||
filesData[containerId] = null;
|
||||
} else {
|
||||
filesData[containerId][fileId] = null;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the containers information.
|
||||
* @return The containers information.
|
||||
*/
|
||||
public ContainersInformation getInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the discardFilesData.
|
||||
* @return the discardFilesData.
|
||||
*/
|
||||
public boolean isDiscardFilesData() {
|
||||
return discardFilesData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the discardFilesData.
|
||||
* @param discardFilesData the discardFilesData to set
|
||||
*/
|
||||
public void setDiscardFilesData(boolean discardFilesData) {
|
||||
this.discardFilesData = discardFilesData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filesData.
|
||||
* @return the filesData.
|
||||
*/
|
||||
public byte[][][] getFilesData() {
|
||||
return filesData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filesData.
|
||||
* @param filesData the filesData to set
|
||||
*/
|
||||
public void setFilesData(byte[][][] filesData) {
|
||||
this.filesData = filesData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cacheFile.
|
||||
* @param cacheFile the cacheFile to set
|
||||
*/
|
||||
public void setCacheFile(CacheFile cacheFile) {
|
||||
this.cacheFile = cacheFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the information.
|
||||
* @param information the information to set
|
||||
*/
|
||||
public void setInformation(ContainersInformation information) {
|
||||
this.information = information;
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package core.cache;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Represents a file used in the server store.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class StoreFile {
|
||||
|
||||
/**
|
||||
* If the data can change during server runtime.
|
||||
*/
|
||||
private boolean dynamic;
|
||||
|
||||
/**
|
||||
* The file data.
|
||||
*/
|
||||
private byte[] data;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code StoreFile} {@code Object}.
|
||||
*/
|
||||
public StoreFile() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the data on the buffer.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void put(ByteBuffer buffer) {
|
||||
byte[] data = new byte[buffer.remaining()];
|
||||
buffer.get(data);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a byte buffer containing the file data.
|
||||
* @return The buffer.
|
||||
*/
|
||||
public ByteBuffer data() {
|
||||
return ByteBuffer.wrap(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data.
|
||||
* @param data The data.
|
||||
*/
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dynamic.
|
||||
* @return The dynamic.
|
||||
*/
|
||||
public boolean isDynamic() {
|
||||
return dynamic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dynamic.
|
||||
* @param dynamic The dynamic to set.
|
||||
*/
|
||||
public void setDynamic(boolean dynamic) {
|
||||
this.dynamic = dynamic;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package core.cache.bzip2;
|
||||
|
||||
public class BZip2BlockEntry {
|
||||
|
||||
boolean aBooleanArray2205[];
|
||||
boolean aBooleanArray2213[];
|
||||
byte aByte2201;
|
||||
byte aByteArray2204[];
|
||||
byte aByteArray2211[];
|
||||
byte aByteArray2212[];
|
||||
byte aByteArray2214[];
|
||||
byte aByteArray2219[];
|
||||
byte aByteArray2224[];
|
||||
byte aByteArrayArray2229[][];
|
||||
int anInt2202;
|
||||
int anInt2203;
|
||||
int anInt2206;
|
||||
int anInt2207;
|
||||
int anInt2208;
|
||||
int anInt2209;
|
||||
int anInt2215;
|
||||
int anInt2216;
|
||||
int anInt2217;
|
||||
int anInt2221;
|
||||
int anInt2222;
|
||||
int anInt2223;
|
||||
int anInt2225;
|
||||
int anInt2227;
|
||||
int anInt2232;
|
||||
int anIntArray2200[];
|
||||
int anIntArray2220[];
|
||||
int anIntArray2226[];
|
||||
int anIntArray2228[];
|
||||
int anIntArrayArray2210[][];
|
||||
int anIntArrayArray2218[][];
|
||||
int anIntArrayArray2230[][];
|
||||
|
||||
public BZip2BlockEntry() {
|
||||
anIntArray2200 = new int[6];
|
||||
anInt2203 = 0;
|
||||
aByteArray2204 = new byte[4096];
|
||||
aByteArray2211 = new byte[256];
|
||||
aByteArray2214 = new byte[18002];
|
||||
aByteArray2219 = new byte[18002];
|
||||
anIntArray2220 = new int[257];
|
||||
anIntArrayArray2218 = new int[6][258];
|
||||
aBooleanArray2205 = new boolean[16];
|
||||
aBooleanArray2213 = new boolean[256];
|
||||
anInt2209 = 0;
|
||||
anIntArray2226 = new int[16];
|
||||
anIntArrayArray2210 = new int[6][258];
|
||||
aByteArrayArray2229 = new byte[6][258];
|
||||
anIntArrayArray2230 = new int[6][258];
|
||||
anIntArray2228 = new int[256];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,532 @@
|
||||
package core.cache.bzip2;
|
||||
|
||||
public class BZip2Decompressor {
|
||||
|
||||
private static int anIntArray257[];
|
||||
private static BZip2BlockEntry entryInstance = new BZip2BlockEntry();
|
||||
|
||||
public static final void decompress(byte decompressedData[], byte packedData[], int containerSize, int blockSize) {
|
||||
synchronized (entryInstance) {
|
||||
entryInstance.aByteArray2224 = packedData;
|
||||
entryInstance.anInt2209 = blockSize;
|
||||
entryInstance.aByteArray2212 = decompressedData;
|
||||
entryInstance.anInt2203 = 0;
|
||||
entryInstance.anInt2206 = decompressedData.length;
|
||||
entryInstance.anInt2232 = 0;
|
||||
entryInstance.anInt2207 = 0;
|
||||
entryInstance.anInt2217 = 0;
|
||||
entryInstance.anInt2216 = 0;
|
||||
method1793(entryInstance);
|
||||
entryInstance.aByteArray2224 = null;
|
||||
entryInstance.aByteArray2212 = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final void method1785(BZip2BlockEntry entry) {
|
||||
entry.anInt2215 = 0;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (entry.aBooleanArray2213[i]) {
|
||||
entry.aByteArray2211[entry.anInt2215] = (byte) i;
|
||||
entry.anInt2215++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final void method1786(int ai[], int ai1[], int ai2[], byte abyte0[], int i, int j, int k) {
|
||||
int l = 0;
|
||||
for (int i1 = i; i1 <= j; i1++) {
|
||||
for (int l2 = 0; l2 < k; l2++) {
|
||||
if (abyte0[l2] == i1) {
|
||||
ai2[l] = l2;
|
||||
l++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (int j1 = 0; j1 < 23; j1++) {
|
||||
ai1[j1] = 0;
|
||||
}
|
||||
|
||||
for (int k1 = 0; k1 < k; k1++) {
|
||||
ai1[abyte0[k1] + 1]++;
|
||||
}
|
||||
|
||||
for (int l1 = 1; l1 < 23; l1++) {
|
||||
ai1[l1] += ai1[l1 - 1];
|
||||
}
|
||||
|
||||
for (int i2 = 0; i2 < 23; i2++) {
|
||||
ai[i2] = 0;
|
||||
}
|
||||
|
||||
int i3 = 0;
|
||||
for (int j2 = i; j2 <= j; j2++) {
|
||||
i3 += ai1[j2 + 1] - ai1[j2];
|
||||
ai[j2] = i3 - 1;
|
||||
i3 <<= 1;
|
||||
}
|
||||
|
||||
for (int k2 = i + 1; k2 <= j; k2++) {
|
||||
ai1[k2] = (ai[k2 - 1] + 1 << 1) - ai1[k2];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final void method1787(BZip2BlockEntry entry) {
|
||||
byte byte4 = entry.aByte2201;
|
||||
int i = entry.anInt2222;
|
||||
int j = entry.anInt2227;
|
||||
int k = entry.anInt2221;
|
||||
int ai[] = anIntArray257;
|
||||
int l = entry.anInt2208;
|
||||
byte abyte0[] = entry.aByteArray2212;
|
||||
int i1 = entry.anInt2203;
|
||||
int j1 = entry.anInt2206;
|
||||
int k1 = j1;
|
||||
int l1 = entry.anInt2225 + 1;
|
||||
label0: do {
|
||||
if (i > 0) {
|
||||
do {
|
||||
if (j1 == 0) {
|
||||
break label0;
|
||||
}
|
||||
if (i == 1) {
|
||||
break;
|
||||
}
|
||||
abyte0[i1] = byte4;
|
||||
i--;
|
||||
i1++;
|
||||
j1--;
|
||||
} while (true);
|
||||
abyte0[i1] = byte4;
|
||||
i1++;
|
||||
j1--;
|
||||
}
|
||||
boolean flag = true;
|
||||
while (flag) {
|
||||
flag = false;
|
||||
if (j == l1) {
|
||||
i = 0;
|
||||
break label0;
|
||||
}
|
||||
byte4 = (byte) k;
|
||||
l = ai[l];
|
||||
byte byte0 = (byte) (l & 0xff);
|
||||
l >>= 8;
|
||||
j++;
|
||||
if (byte0 != k) {
|
||||
k = byte0;
|
||||
if (j1 == 0) {
|
||||
i = 1;
|
||||
} else {
|
||||
abyte0[i1] = byte4;
|
||||
i1++;
|
||||
j1--;
|
||||
flag = true;
|
||||
continue;
|
||||
}
|
||||
break label0;
|
||||
}
|
||||
if (j != l1) {
|
||||
continue;
|
||||
}
|
||||
if (j1 == 0) {
|
||||
i = 1;
|
||||
break label0;
|
||||
}
|
||||
abyte0[i1] = byte4;
|
||||
i1++;
|
||||
j1--;
|
||||
flag = true;
|
||||
}
|
||||
i = 2;
|
||||
l = ai[l];
|
||||
byte byte1 = (byte) (l & 0xff);
|
||||
l >>= 8;
|
||||
if (++j != l1) {
|
||||
if (byte1 != k) {
|
||||
k = byte1;
|
||||
} else {
|
||||
i = 3;
|
||||
l = ai[l];
|
||||
byte byte2 = (byte) (l & 0xff);
|
||||
l >>= 8;
|
||||
if (++j != l1) {
|
||||
if (byte2 != k) {
|
||||
k = byte2;
|
||||
} else {
|
||||
l = ai[l];
|
||||
byte byte3 = (byte) (l & 0xff);
|
||||
l >>= 8;
|
||||
j++;
|
||||
i = (byte3 & 0xff) + 4;
|
||||
l = ai[l];
|
||||
k = (byte) (l & 0xff);
|
||||
l >>= 8;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (true);
|
||||
entry.anInt2216 += k1 - j1;
|
||||
entry.aByte2201 = byte4;
|
||||
entry.anInt2222 = i;
|
||||
entry.anInt2227 = j;
|
||||
entry.anInt2221 = k;
|
||||
anIntArray257 = ai;
|
||||
entry.anInt2208 = l;
|
||||
entry.aByteArray2212 = abyte0;
|
||||
entry.anInt2203 = i1;
|
||||
entry.anInt2206 = j1;
|
||||
}
|
||||
|
||||
private static final byte method1788(BZip2BlockEntry entry) {
|
||||
return (byte) method1790(1, entry);
|
||||
}
|
||||
|
||||
private static final byte method1789(BZip2BlockEntry entryInstance2) {
|
||||
return (byte) method1790(8, entryInstance2);
|
||||
}
|
||||
|
||||
private static final int method1790(int i, BZip2BlockEntry entry) {
|
||||
int j;
|
||||
do {
|
||||
if (entry.anInt2232 >= i) {
|
||||
int k = entry.anInt2207 >> entry.anInt2232 - i & (1 << i) - 1;
|
||||
entry.anInt2232 -= i;
|
||||
j = k;
|
||||
break;
|
||||
}
|
||||
entry.anInt2207 = entry.anInt2207 << 8 | entry.aByteArray2224[entry.anInt2209] & 0xff;
|
||||
entry.anInt2232 += 8;
|
||||
entry.anInt2209++;
|
||||
entry.anInt2217++;
|
||||
} while (true);
|
||||
return j;
|
||||
}
|
||||
|
||||
public static void clearBlockEntryInstance() {
|
||||
entryInstance = null;
|
||||
}
|
||||
|
||||
private static final void method1793(BZip2BlockEntry entryInstance2) {
|
||||
// unused
|
||||
/*
|
||||
* boolean flag = false; boolean flag1 = false; boolean flag2 = false;
|
||||
* boolean flag3 = false; boolean flag4 = false; boolean flag5 = false;
|
||||
* boolean flag6 = false; boolean flag7 = false; boolean flag8 = false;
|
||||
* boolean flag9 = false; boolean flag10 = false; boolean flag11 =
|
||||
* false; boolean flag12 = false; boolean flag13 = false; boolean flag14
|
||||
* = false; boolean flag15 = false; boolean flag16 = false; boolean
|
||||
* flag17 = false;
|
||||
*/
|
||||
int j8 = 0;
|
||||
int ai[] = null;
|
||||
int ai1[] = null;
|
||||
int ai2[] = null;
|
||||
entryInstance2.anInt2202 = 1;
|
||||
if (anIntArray257 == null) {
|
||||
anIntArray257 = new int[entryInstance2.anInt2202 * 0x186a0];
|
||||
}
|
||||
boolean flag18 = true;
|
||||
while (flag18) {
|
||||
byte byte0 = method1789(entryInstance2);
|
||||
if (byte0 == 23) {
|
||||
return;
|
||||
}
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1789(entryInstance2);
|
||||
byte0 = method1788(entryInstance2);
|
||||
entryInstance2.anInt2223 = 0;
|
||||
byte0 = method1789(entryInstance2);
|
||||
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
|
||||
byte0 = method1789(entryInstance2);
|
||||
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
|
||||
byte0 = method1789(entryInstance2);
|
||||
entryInstance2.anInt2223 = entryInstance2.anInt2223 << 8 | byte0 & 0xff;
|
||||
for (int j = 0; j < 16; j++) {
|
||||
byte byte1 = method1788(entryInstance2);
|
||||
if (byte1 == 1) {
|
||||
entryInstance2.aBooleanArray2205[j] = true;
|
||||
} else {
|
||||
entryInstance2.aBooleanArray2205[j] = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int k = 0; k < 256; k++) {
|
||||
entryInstance2.aBooleanArray2213[k] = false;
|
||||
}
|
||||
|
||||
for (int l = 0; l < 16; l++) {
|
||||
if (entryInstance2.aBooleanArray2205[l]) {
|
||||
for (int i3 = 0; i3 < 16; i3++) {
|
||||
byte byte2 = method1788(entryInstance2);
|
||||
if (byte2 == 1) {
|
||||
entryInstance2.aBooleanArray2213[l * 16 + i3] = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
method1785(entryInstance2);
|
||||
int i4 = entryInstance2.anInt2215 + 2;
|
||||
int j4 = method1790(3, entryInstance2);
|
||||
int k4 = method1790(15, entryInstance2);
|
||||
for (int i1 = 0; i1 < k4; i1++) {
|
||||
int j3 = 0;
|
||||
do {
|
||||
byte byte3 = method1788(entryInstance2);
|
||||
if (byte3 == 0) {
|
||||
break;
|
||||
}
|
||||
j3++;
|
||||
} while (true);
|
||||
entryInstance2.aByteArray2214[i1] = (byte) j3;
|
||||
}
|
||||
|
||||
byte abyte0[] = new byte[6];
|
||||
for (byte byte16 = 0; byte16 < j4; byte16++) {
|
||||
abyte0[byte16] = byte16;
|
||||
}
|
||||
|
||||
for (int j1 = 0; j1 < k4; j1++) {
|
||||
byte byte17 = entryInstance2.aByteArray2214[j1];
|
||||
byte byte15 = abyte0[byte17];
|
||||
for (; byte17 > 0; byte17--) {
|
||||
abyte0[byte17] = abyte0[byte17 - 1];
|
||||
}
|
||||
|
||||
abyte0[0] = byte15;
|
||||
entryInstance2.aByteArray2219[j1] = byte15;
|
||||
}
|
||||
|
||||
for (int k3 = 0; k3 < j4; k3++) {
|
||||
int k6 = method1790(5, entryInstance2);
|
||||
for (int k1 = 0; k1 < i4; k1++) {
|
||||
do {
|
||||
byte byte4 = method1788(entryInstance2);
|
||||
if (byte4 == 0) {
|
||||
break;
|
||||
}
|
||||
byte4 = method1788(entryInstance2);
|
||||
if (byte4 == 0) {
|
||||
k6++;
|
||||
} else {
|
||||
k6--;
|
||||
}
|
||||
} while (true);
|
||||
entryInstance2.aByteArrayArray2229[k3][k1] = (byte) k6;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (int l3 = 0; l3 < j4; l3++) {
|
||||
byte byte8 = 32;
|
||||
int i = 0;
|
||||
for (int l1 = 0; l1 < i4; l1++) {
|
||||
if (entryInstance2.aByteArrayArray2229[l3][l1] > i) {
|
||||
i = entryInstance2.aByteArrayArray2229[l3][l1];
|
||||
}
|
||||
if (entryInstance2.aByteArrayArray2229[l3][l1] < byte8) {
|
||||
byte8 = entryInstance2.aByteArrayArray2229[l3][l1];
|
||||
}
|
||||
}
|
||||
|
||||
method1786(entryInstance2.anIntArrayArray2230[l3], entryInstance2.anIntArrayArray2218[l3], entryInstance2.anIntArrayArray2210[l3], entryInstance2.aByteArrayArray2229[l3], byte8, i, i4);
|
||||
entryInstance2.anIntArray2200[l3] = byte8;
|
||||
}
|
||||
|
||||
int l4 = entryInstance2.anInt2215 + 1;
|
||||
int i5 = -1;
|
||||
int j5 = 0;
|
||||
for (int i2 = 0; i2 <= 255; i2++) {
|
||||
entryInstance2.anIntArray2228[i2] = 0;
|
||||
}
|
||||
|
||||
int i9 = 4095;
|
||||
for (int k8 = 15; k8 >= 0; k8--) {
|
||||
for (int l8 = 15; l8 >= 0; l8--) {
|
||||
entryInstance2.aByteArray2204[i9] = (byte) (k8 * 16 + l8);
|
||||
i9--;
|
||||
}
|
||||
|
||||
entryInstance2.anIntArray2226[k8] = i9 + 1;
|
||||
}
|
||||
|
||||
int l5 = 0;
|
||||
if (j5 == 0) {
|
||||
i5++;
|
||||
j5 = 50;
|
||||
byte byte12 = entryInstance2.aByteArray2219[i5];
|
||||
j8 = entryInstance2.anIntArray2200[byte12];
|
||||
ai = entryInstance2.anIntArrayArray2230[byte12];
|
||||
ai2 = entryInstance2.anIntArrayArray2210[byte12];
|
||||
ai1 = entryInstance2.anIntArrayArray2218[byte12];
|
||||
}
|
||||
j5--;
|
||||
int l6 = j8;
|
||||
int k7;
|
||||
byte byte9;
|
||||
for (k7 = method1790(l6, entryInstance2); k7 > ai[l6]; k7 = k7 << 1 | byte9) {
|
||||
l6++;
|
||||
byte9 = method1788(entryInstance2);
|
||||
}
|
||||
|
||||
for (int k5 = ai2[k7 - ai1[l6]]; k5 != l4;) {
|
||||
if (k5 == 0 || k5 == 1) {
|
||||
int i6 = -1;
|
||||
int j6 = 1;
|
||||
do {
|
||||
if (k5 == 0) {
|
||||
i6 += j6;
|
||||
} else if (k5 == 1) {
|
||||
i6 += 2 * j6;
|
||||
}
|
||||
j6 *= 2;
|
||||
if (j5 == 0) {
|
||||
i5++;
|
||||
j5 = 50;
|
||||
byte byte13 = entryInstance2.aByteArray2219[i5];
|
||||
j8 = entryInstance2.anIntArray2200[byte13];
|
||||
ai = entryInstance2.anIntArrayArray2230[byte13];
|
||||
ai2 = entryInstance2.anIntArrayArray2210[byte13];
|
||||
ai1 = entryInstance2.anIntArrayArray2218[byte13];
|
||||
}
|
||||
j5--;
|
||||
int i7 = j8;
|
||||
int l7;
|
||||
byte byte10;
|
||||
for (l7 = method1790(i7, entryInstance2); l7 > ai[i7]; l7 = l7 << 1 | byte10) {
|
||||
i7++;
|
||||
byte10 = method1788(entryInstance2);
|
||||
}
|
||||
|
||||
k5 = ai2[l7 - ai1[i7]];
|
||||
} while (k5 == 0 || k5 == 1);
|
||||
i6++;
|
||||
byte byte5 = entryInstance2.aByteArray2211[entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[0]] & 0xff];
|
||||
entryInstance2.anIntArray2228[byte5 & 0xff] += i6;
|
||||
for (; i6 > 0; i6--) {
|
||||
anIntArray257[l5] = byte5 & 0xff;
|
||||
l5++;
|
||||
}
|
||||
|
||||
} else {
|
||||
int i11 = k5 - 1;
|
||||
byte byte6;
|
||||
if (i11 < 16) {
|
||||
int i10 = entryInstance2.anIntArray2226[0];
|
||||
byte6 = entryInstance2.aByteArray2204[i10 + i11];
|
||||
for (; i11 > 3; i11 -= 4) {
|
||||
int j11 = i10 + i11;
|
||||
entryInstance2.aByteArray2204[j11] = entryInstance2.aByteArray2204[j11 - 1];
|
||||
entryInstance2.aByteArray2204[j11 - 1] = entryInstance2.aByteArray2204[j11 - 2];
|
||||
entryInstance2.aByteArray2204[j11 - 2] = entryInstance2.aByteArray2204[j11 - 3];
|
||||
entryInstance2.aByteArray2204[j11 - 3] = entryInstance2.aByteArray2204[j11 - 4];
|
||||
}
|
||||
|
||||
for (; i11 > 0; i11--) {
|
||||
entryInstance2.aByteArray2204[i10 + i11] = entryInstance2.aByteArray2204[(i10 + i11) - 1];
|
||||
}
|
||||
|
||||
entryInstance2.aByteArray2204[i10] = byte6;
|
||||
} else {
|
||||
int k10 = i11 / 16;
|
||||
int l10 = i11 % 16;
|
||||
int j10 = entryInstance2.anIntArray2226[k10] + l10;
|
||||
byte6 = entryInstance2.aByteArray2204[j10];
|
||||
for (; j10 > entryInstance2.anIntArray2226[k10]; j10--) {
|
||||
entryInstance2.aByteArray2204[j10] = entryInstance2.aByteArray2204[j10 - 1];
|
||||
}
|
||||
|
||||
entryInstance2.anIntArray2226[k10]++;
|
||||
for (; k10 > 0; k10--) {
|
||||
entryInstance2.anIntArray2226[k10]--;
|
||||
entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[k10]] = entryInstance2.aByteArray2204[(entryInstance2.anIntArray2226[k10 - 1] + 16) - 1];
|
||||
}
|
||||
|
||||
entryInstance2.anIntArray2226[0]--;
|
||||
entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[0]] = byte6;
|
||||
if (entryInstance2.anIntArray2226[0] == 0) {
|
||||
int l9 = 4095;
|
||||
for (int j9 = 15; j9 >= 0; j9--) {
|
||||
for (int k9 = 15; k9 >= 0; k9--) {
|
||||
entryInstance2.aByteArray2204[l9] = entryInstance2.aByteArray2204[entryInstance2.anIntArray2226[j9] + k9];
|
||||
l9--;
|
||||
}
|
||||
|
||||
entryInstance2.anIntArray2226[j9] = l9 + 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
entryInstance2.anIntArray2228[entryInstance2.aByteArray2211[byte6 & 0xff] & 0xff]++;
|
||||
anIntArray257[l5] = entryInstance2.aByteArray2211[byte6 & 0xff] & 0xff;
|
||||
l5++;
|
||||
if (j5 == 0) {
|
||||
i5++;
|
||||
j5 = 50;
|
||||
byte byte14 = entryInstance2.aByteArray2219[i5];
|
||||
j8 = entryInstance2.anIntArray2200[byte14];
|
||||
ai = entryInstance2.anIntArrayArray2230[byte14];
|
||||
ai2 = entryInstance2.anIntArrayArray2210[byte14];
|
||||
ai1 = entryInstance2.anIntArrayArray2218[byte14];
|
||||
}
|
||||
j5--;
|
||||
int j7 = j8;
|
||||
int i8;
|
||||
byte byte11;
|
||||
for (i8 = method1790(j7, entryInstance2); i8 > ai[j7]; i8 = i8 << 1 | byte11) {
|
||||
j7++;
|
||||
byte11 = method1788(entryInstance2);
|
||||
}
|
||||
|
||||
k5 = ai2[i8 - ai1[j7]];
|
||||
}
|
||||
}
|
||||
|
||||
entryInstance2.anInt2222 = 0;
|
||||
entryInstance2.aByte2201 = 0;
|
||||
entryInstance2.anIntArray2220[0] = 0;
|
||||
for (int j2 = 1; j2 <= 256; j2++) {
|
||||
entryInstance2.anIntArray2220[j2] = entryInstance2.anIntArray2228[j2 - 1];
|
||||
}
|
||||
|
||||
for (int k2 = 1; k2 <= 256; k2++) {
|
||||
entryInstance2.anIntArray2220[k2] += entryInstance2.anIntArray2220[k2 - 1];
|
||||
}
|
||||
|
||||
for (int l2 = 0; l2 < l5; l2++) {
|
||||
byte byte7 = (byte) (anIntArray257[l2] & 0xff);
|
||||
anIntArray257[entryInstance2.anIntArray2220[byte7 & 0xff]] |= l2 << 8;
|
||||
entryInstance2.anIntArray2220[byte7 & 0xff]++;
|
||||
}
|
||||
|
||||
entryInstance2.anInt2208 = anIntArray257[entryInstance2.anInt2223] >> 8;
|
||||
entryInstance2.anInt2227 = 0;
|
||||
entryInstance2.anInt2208 = anIntArray257[entryInstance2.anInt2208];
|
||||
entryInstance2.anInt2221 = (byte) (entryInstance2.anInt2208 & 0xff);
|
||||
entryInstance2.anInt2208 >>= 8;
|
||||
entryInstance2.anInt2227++;
|
||||
entryInstance2.anInt2225 = l5;
|
||||
method1787(entryInstance2);
|
||||
if (entryInstance2.anInt2227 == entryInstance2.anInt2225 + 1 && entryInstance2.anInt2222 == 0) {
|
||||
flag18 = true;
|
||||
} else {
|
||||
flag18 = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
package core.cache.crypto;
|
||||
|
||||
/**
|
||||
* <p> An implementation of an ISAAC cipher. See <a
|
||||
* href="http://en.wikipedia.org/wiki/ISAAC_(cipher)">
|
||||
* http://en.wikipedia.org/wiki/ISAAC_(cipher)</a> for more information. </p>
|
||||
* <p> This implementation is based on the one written by Bob Jenkins, which is
|
||||
* available at <a href="http://www.burtleburtle.net/bob/java/rand/Rand.java">
|
||||
* http://www.burtleburtle.net/bob/java/rand/Rand.java</a>. </p>
|
||||
* @author Graham Edgecombe
|
||||
*/
|
||||
public class ISAACCipher {
|
||||
|
||||
/**
|
||||
* The golden ratio.
|
||||
*/
|
||||
public static final int RATIO = 0x9e3779b9;
|
||||
|
||||
/**
|
||||
* The log of the size of the results and memory arrays.
|
||||
*/
|
||||
public static final int SIZE_LOG = 8;
|
||||
|
||||
/**
|
||||
* The size of the results and memory arrays.
|
||||
*/
|
||||
public static final int SIZE = 1 << SIZE_LOG;
|
||||
|
||||
/**
|
||||
* For pseudorandom lookup.
|
||||
*/
|
||||
public static final int MASK = (SIZE - 1) << 2;
|
||||
|
||||
/**
|
||||
* The count through the results.
|
||||
*/
|
||||
private int count = 0;
|
||||
|
||||
/**
|
||||
* The results.
|
||||
*/
|
||||
private int results[] = new int[SIZE];
|
||||
|
||||
/**
|
||||
* The internal memory state.
|
||||
*/
|
||||
private int memory[] = new int[SIZE];
|
||||
|
||||
/**
|
||||
* The accumulator.
|
||||
*/
|
||||
private int a;
|
||||
|
||||
/**
|
||||
* The last result.
|
||||
*/
|
||||
private int b;
|
||||
|
||||
/**
|
||||
* The counter.
|
||||
*/
|
||||
private int c;
|
||||
|
||||
/**
|
||||
* Creates the ISAAC cipher.
|
||||
* @param seed The seed.
|
||||
*/
|
||||
public ISAACCipher(int[] seed) {
|
||||
for (int i = 0; i < seed.length; i++) {
|
||||
results[i] = seed[i];
|
||||
}
|
||||
init(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next value.
|
||||
* @return The next value.
|
||||
*/
|
||||
public int getNextValue() {
|
||||
if (count-- == 0) {
|
||||
isaac();
|
||||
count = SIZE - 1;
|
||||
}
|
||||
return 0;//results[count];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates 256 results.
|
||||
*/
|
||||
public void isaac() {
|
||||
int i, j, x, y;
|
||||
b += ++c;
|
||||
for (i = 0, j = SIZE / 2; i < SIZE / 2;) {
|
||||
x = memory[i];
|
||||
a ^= a << 13;
|
||||
a += memory[j++];
|
||||
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
|
||||
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
|
||||
|
||||
x = memory[i];
|
||||
a ^= a >>> 6;
|
||||
a += memory[j++];
|
||||
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
|
||||
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
|
||||
|
||||
x = memory[i];
|
||||
a ^= a << 2;
|
||||
a += memory[j++];
|
||||
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
|
||||
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
|
||||
|
||||
x = memory[i];
|
||||
a ^= a >>> 16;
|
||||
a += memory[j++];
|
||||
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
|
||||
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
|
||||
}
|
||||
for (j = 0; j < SIZE / 2;) {
|
||||
x = memory[i];
|
||||
a ^= a << 13;
|
||||
a += memory[j++];
|
||||
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
|
||||
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
|
||||
|
||||
x = memory[i];
|
||||
a ^= a >>> 6;
|
||||
a += memory[j++];
|
||||
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
|
||||
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
|
||||
|
||||
x = memory[i];
|
||||
a ^= a << 2;
|
||||
a += memory[j++];
|
||||
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
|
||||
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
|
||||
|
||||
x = memory[i];
|
||||
a ^= a >>> 16;
|
||||
a += memory[j++];
|
||||
memory[i] = y = memory[(x & MASK) >> 2] + a + b;
|
||||
results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the ISAAC.
|
||||
* @param flag Flag indicating if we should perform a second pass.
|
||||
*/
|
||||
public void init(boolean flag) {
|
||||
int i;
|
||||
int a, b, c, d, e, f, g, h;
|
||||
a = b = c = d = e = f = g = h = RATIO;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
a ^= b << 11;
|
||||
d += a;
|
||||
b += c;
|
||||
b ^= c >>> 2;
|
||||
e += b;
|
||||
c += d;
|
||||
c ^= d << 8;
|
||||
f += c;
|
||||
d += e;
|
||||
d ^= e >>> 16;
|
||||
g += d;
|
||||
e += f;
|
||||
e ^= f << 10;
|
||||
h += e;
|
||||
f += g;
|
||||
f ^= g >>> 4;
|
||||
a += f;
|
||||
g += h;
|
||||
g ^= h << 8;
|
||||
b += g;
|
||||
h += a;
|
||||
h ^= a >>> 9;
|
||||
c += h;
|
||||
a += b;
|
||||
}
|
||||
for (i = 0; i < SIZE; i += 8) {
|
||||
if (flag) {
|
||||
a += results[i];
|
||||
b += results[i + 1];
|
||||
c += results[i + 2];
|
||||
d += results[i + 3];
|
||||
e += results[i + 4];
|
||||
f += results[i + 5];
|
||||
g += results[i + 6];
|
||||
h += results[i + 7];
|
||||
}
|
||||
a ^= b << 11;
|
||||
d += a;
|
||||
b += c;
|
||||
b ^= c >>> 2;
|
||||
e += b;
|
||||
c += d;
|
||||
c ^= d << 8;
|
||||
f += c;
|
||||
d += e;
|
||||
d ^= e >>> 16;
|
||||
g += d;
|
||||
e += f;
|
||||
e ^= f << 10;
|
||||
h += e;
|
||||
f += g;
|
||||
f ^= g >>> 4;
|
||||
a += f;
|
||||
g += h;
|
||||
g ^= h << 8;
|
||||
b += g;
|
||||
h += a;
|
||||
h ^= a >>> 9;
|
||||
c += h;
|
||||
a += b;
|
||||
memory[i] = a;
|
||||
memory[i + 1] = b;
|
||||
memory[i + 2] = c;
|
||||
memory[i + 3] = d;
|
||||
memory[i + 4] = e;
|
||||
memory[i + 5] = f;
|
||||
memory[i + 6] = g;
|
||||
memory[i + 7] = h;
|
||||
}
|
||||
if (flag) {
|
||||
for (i = 0; i < SIZE; i += 8) {
|
||||
a += memory[i];
|
||||
b += memory[i + 1];
|
||||
c += memory[i + 2];
|
||||
d += memory[i + 3];
|
||||
e += memory[i + 4];
|
||||
f += memory[i + 5];
|
||||
g += memory[i + 6];
|
||||
h += memory[i + 7];
|
||||
a ^= b << 11;
|
||||
d += a;
|
||||
b += c;
|
||||
b ^= c >>> 2;
|
||||
e += b;
|
||||
c += d;
|
||||
c ^= d << 8;
|
||||
f += c;
|
||||
d += e;
|
||||
d ^= e >>> 16;
|
||||
g += d;
|
||||
e += f;
|
||||
e ^= f << 10;
|
||||
h += e;
|
||||
f += g;
|
||||
f ^= g >>> 4;
|
||||
a += f;
|
||||
g += h;
|
||||
g ^= h << 8;
|
||||
b += g;
|
||||
h += a;
|
||||
h ^= a >>> 9;
|
||||
c += h;
|
||||
a += b;
|
||||
memory[i] = a;
|
||||
memory[i + 1] = b;
|
||||
memory[i + 2] = c;
|
||||
memory[i + 3] = d;
|
||||
memory[i + 4] = e;
|
||||
memory[i + 5] = f;
|
||||
memory[i + 6] = g;
|
||||
memory[i + 7] = h;
|
||||
}
|
||||
}
|
||||
isaac();
|
||||
count = SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package core.cache.crypto;
|
||||
|
||||
/**
|
||||
* Represents a ISAAC key pair, for both input and output.
|
||||
* @author `Discardedx2
|
||||
*/
|
||||
public final class ISAACPair {
|
||||
|
||||
/**
|
||||
* The input cipher.
|
||||
*/
|
||||
private ISAACCipher input;
|
||||
|
||||
/**
|
||||
* The output cipher.
|
||||
*/
|
||||
private ISAACCipher output;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ISAACPair} {@code Object}.
|
||||
* @param input The input cipher.
|
||||
* @param output The output cipher.
|
||||
*/
|
||||
public ISAACPair(ISAACCipher input, ISAACCipher output) {
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input cipher.
|
||||
* @return The input cipher.
|
||||
*/
|
||||
public ISAACCipher getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output cipher.
|
||||
* @return The output cipher.
|
||||
*/
|
||||
public ISAACCipher getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
package core.cache.crypto;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Holds XTEA cryption methods.
|
||||
* @author ?
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class XTEACryption {
|
||||
|
||||
/**
|
||||
* The delta value
|
||||
*/
|
||||
private static final int DELTA = -1640531527;
|
||||
|
||||
/**
|
||||
* The sum.
|
||||
*/
|
||||
private static final int SUM = -957401312;
|
||||
|
||||
/**
|
||||
* The amount of "cryption cycles".
|
||||
*/
|
||||
private static final int NUM_ROUNDS = 32;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code XTEACryption}.
|
||||
*/
|
||||
private XTEACryption() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the contents of the buffer.
|
||||
* @param keys The cryption keys.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public static ByteBuffer decrypt(int[] keys, ByteBuffer buffer) {
|
||||
return decrypt(keys, buffer, buffer.position(), buffer.limit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the buffer data.
|
||||
* @param keys The keys.
|
||||
* @param buffer The buffer to decrypt.
|
||||
* @param offset The offset of the data to decrypt.
|
||||
* @param length The length.
|
||||
* @return The decrypted data.
|
||||
*/
|
||||
public static ByteBuffer decrypt(int[] keys, ByteBuffer buffer, int offset, int length) {
|
||||
int numBlocks = (length - offset) / 8;
|
||||
int[] block = new int[2];
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
int index = i * 8 + offset;
|
||||
block[0] = buffer.getInt(index);
|
||||
block[1] = buffer.getInt(index + 4);
|
||||
decipher(keys, block);
|
||||
buffer.putInt(index, block[0]);
|
||||
buffer.putInt(index + 4, block[1]);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deciphers the values.
|
||||
* @param keys The cryption key.
|
||||
* @param block The values to decipher.
|
||||
*/
|
||||
private static void decipher(int[] keys, int[] block) {
|
||||
long sum = SUM;
|
||||
for (int i = 0; i < NUM_ROUNDS; i++) {
|
||||
block[1] -= (keys[(int) ((sum & 0x1933) >>> 11)] + sum ^ block[0] + (block[0] << 4 ^ block[0] >>> 5));
|
||||
sum -= DELTA;
|
||||
block[0] -= ((block[1] << 4 ^ block[1] >>> 5) + block[1] ^ keys[(int) (sum & 0x3)] + sum);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts the contents of the byte buffer.
|
||||
* @param keys The cryption keys.
|
||||
* @param buffer The buffer to encrypt.
|
||||
*/
|
||||
public static void encrypt(int[] keys, ByteBuffer buffer) {
|
||||
encrypt(keys, buffer, buffer.position(), buffer.limit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts the buffer data.
|
||||
* @param keys The keys.
|
||||
* @param buffer The buffer to encrypt.
|
||||
* @param offset The offset of the data to encrypt.
|
||||
* @param length The length.
|
||||
* @return The encrypted data.
|
||||
*/
|
||||
public static void encrypt(int[] keys, ByteBuffer buffer, int offset, int length) {
|
||||
int numBlocks = (length - offset) / 8;
|
||||
int[] block = new int[2];
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
int index = i * 8 + offset;
|
||||
block[0] = buffer.getInt(index);
|
||||
block[1] = buffer.getInt(index + 4);
|
||||
encipher(keys, block);
|
||||
buffer.putInt(index, block[0]);
|
||||
buffer.putInt(index + 4, block[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enciphers the values of the block.
|
||||
* @param keys The cryption keys.
|
||||
* @param block The block to encipher.
|
||||
*/
|
||||
private static void encipher(int[] keys, int[] block) {
|
||||
long sum = 0;
|
||||
for (int i = 0; i < NUM_ROUNDS; i++) {
|
||||
block[0] += ((block[1] << 4 ^ block[1] >>> 5) + block[1] ^ keys[(int) (sum & 0x3)] + sum);
|
||||
sum += DELTA;
|
||||
block[1] += (keys[(int) ((sum & 0x1933) >>> 11)] + sum ^ block[0] + (block[0] << 4 ^ block[0] >>> 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
package core.cache.def;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import core.tools.StringUtils;
|
||||
import core.game.node.Node;
|
||||
|
||||
/**
|
||||
* Represent's a node's definitions.
|
||||
* @author Emperor
|
||||
* @param <T> The node type.
|
||||
*/
|
||||
public class Definition<T extends Node> {
|
||||
|
||||
/**
|
||||
* The node id.
|
||||
*/
|
||||
protected int id;
|
||||
|
||||
/**
|
||||
* The name.
|
||||
*/
|
||||
protected String name = "null";
|
||||
|
||||
/**
|
||||
* The examine info.
|
||||
*/
|
||||
protected String examine;
|
||||
|
||||
/**
|
||||
* The options.
|
||||
*/
|
||||
protected String[] options;
|
||||
|
||||
/**
|
||||
* The configurations.
|
||||
*/
|
||||
protected final Map<String, Object> handlers = new HashMap<String, Object>();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Definition} {@code Object}.
|
||||
*/
|
||||
public Definition() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this node has options.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public boolean hasOptions() {
|
||||
return hasOptions(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this node has options.
|
||||
* @param examine If examine should be treated as an option.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public boolean hasOptions(boolean examine) {
|
||||
if (name.equals("null") || options == null) {
|
||||
return false;
|
||||
}
|
||||
for (String option : options) {
|
||||
if (option != null && !option.equals("null")) {
|
||||
if (examine || !option.equals("Examine")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a configuration of this item's definitions.
|
||||
* @param key The key.
|
||||
* @return The configuration value.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> V getConfiguration(String key) {
|
||||
return (V) handlers.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a configuration from this item's definitions.
|
||||
* @param key The key.
|
||||
* @param fail The object to return if there was no value found for this
|
||||
* key.
|
||||
* @return The value, or the fail object.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> V getConfiguration(String key, V fail) {
|
||||
V object = (V) handlers.get(key);
|
||||
if (object == null) {
|
||||
return fail;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id.
|
||||
* @return The id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id.
|
||||
* @param id The id to set.
|
||||
*/
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name.
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name.
|
||||
* @param name The name to set.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the examine.
|
||||
* @return The examine.
|
||||
*/
|
||||
public String getExamine() {
|
||||
if (examine == null) {
|
||||
try {
|
||||
if(handlers.get("examine") != null)
|
||||
examine = handlers.get("examine").toString();
|
||||
} catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
if(examine == null) {
|
||||
if (name.length() > 0) {
|
||||
examine = "It's a" + (StringUtils.isPlusN(name) ? "n " : " ") + name + ".";
|
||||
} else {
|
||||
examine = "null";
|
||||
}
|
||||
}
|
||||
}
|
||||
return examine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the examine.
|
||||
* @param examine The examine to set.
|
||||
*/
|
||||
public void setExamine(String examine) {
|
||||
this.examine = examine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the options.
|
||||
* @return The options.
|
||||
*/
|
||||
public String[] getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options.
|
||||
* @param options The options to set.
|
||||
*/
|
||||
public void setOptions(String[] options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configurations.
|
||||
* @return The configurations.
|
||||
*/
|
||||
public Map<String, Object> getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package core.cache.def.impl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import core.cache.Cache;
|
||||
import core.cache.misc.buffer.ByteBufferUtils;
|
||||
|
||||
/**
|
||||
* Represents an animation's definitions.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class AnimationDefinition {
|
||||
|
||||
public int anInt2136;
|
||||
public int anInt2137;
|
||||
public int[] anIntArray2139;
|
||||
public int anInt2140;
|
||||
public boolean aBoolean2141 = false;
|
||||
public int anInt2142;
|
||||
public int emoteItem;
|
||||
public int anInt2144 = -1;
|
||||
public int[][] handledSounds;
|
||||
public boolean[] aBooleanArray2149;
|
||||
public int[] anIntArray2151;
|
||||
public boolean aBoolean2152;
|
||||
public int[] durations;
|
||||
public int anInt2155;
|
||||
public boolean aBoolean2158;
|
||||
public boolean aBoolean2159;
|
||||
public int anInt2162;
|
||||
public int anInt2163;
|
||||
boolean newHeader;
|
||||
|
||||
// added
|
||||
public int[] soundMinDelay;
|
||||
public int[] soundMaxDelay;
|
||||
public int[] anIntArray1362;
|
||||
public boolean effect2Sound;
|
||||
|
||||
private static final Map<Integer, AnimationDefinition> animDefs = new HashMap<>();
|
||||
|
||||
public static final AnimationDefinition forId(int emoteId) {
|
||||
try {
|
||||
AnimationDefinition defs = animDefs.get(emoteId);
|
||||
if (defs != null) {
|
||||
return defs;
|
||||
}
|
||||
byte[] data = Cache.getIndexes()[20].getFileData(emoteId >>> 7, emoteId & 0x7f);
|
||||
defs = new AnimationDefinition();
|
||||
if (data != null) {
|
||||
defs.readValueLoop(ByteBuffer.wrap(data));
|
||||
}
|
||||
defs.method2394();
|
||||
animDefs.put(emoteId, defs);
|
||||
return defs;
|
||||
} catch (Throwable t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void readValueLoop(ByteBuffer buffer) {
|
||||
for (;;) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
if (opcode == 0) {
|
||||
break;
|
||||
}
|
||||
readValues(buffer, opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration of this animation in milliseconds.
|
||||
* @return The duration.
|
||||
*/
|
||||
public int getDuration() {
|
||||
if (durations == null) {
|
||||
return 0;
|
||||
}
|
||||
int duration = 0;
|
||||
for (int i : durations) {
|
||||
if (i > 100) {
|
||||
continue;
|
||||
}
|
||||
duration += i * 20;
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration of this animation in (600ms) ticks.
|
||||
* @return The duration in ticks.
|
||||
*/
|
||||
public int getDurationTicks() {
|
||||
int ticks = getDuration() / 600;
|
||||
return Math.max(ticks, 1);
|
||||
}
|
||||
|
||||
private void readValues(ByteBuffer buffer, int opcode) {
|
||||
if (opcode == 1) {
|
||||
int length = buffer.getShort() & 0xFFFF;
|
||||
durations = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
durations[i] = buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
anIntArray2139 = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
anIntArray2139[i] = buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
anIntArray2139[i] = ((buffer.getShort() & 0xFFFF << 16) + anIntArray2139[i]);
|
||||
}
|
||||
} else if (opcode != 2) {
|
||||
if (opcode != 3) {
|
||||
if (opcode == 4)
|
||||
aBoolean2152 = true;
|
||||
else if (opcode == 5)
|
||||
anInt2142 = buffer.get() & 0xFF;
|
||||
else if (opcode != 6) {
|
||||
if (opcode == 7)
|
||||
emoteItem = buffer.getShort() & 0xFFFF;
|
||||
else if ((opcode ^ 0xffffffff) != -9) {
|
||||
if (opcode != 9) {
|
||||
if (opcode != 10) {
|
||||
if (opcode == 11)
|
||||
anInt2155 = buffer.get() & 0xFF;
|
||||
else if (opcode == 12) {
|
||||
int i = buffer.get() & 0xFF;
|
||||
anIntArray2151 = new int[i];
|
||||
for (int i_19_ = 0; ((i_19_ ^ 0xffffffff) > (i ^ 0xffffffff)); i_19_++) {
|
||||
anIntArray2151[i_19_] = buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
for (int i_20_ = 0; i > i_20_; i_20_++)
|
||||
anIntArray2151[i_20_] = ((buffer.getShort() & 0xFFFF << 16) + anIntArray2151[i_20_]);
|
||||
} else if (opcode == 13) {
|
||||
// opcode 13
|
||||
int i = buffer.getShort() & 0xFFFF;
|
||||
handledSounds = new int[i][];
|
||||
for (int i_21_ = 0; i_21_ < i; i_21_++) {
|
||||
int i_22_ = buffer.get() & 0xFF;
|
||||
if ((i_22_ ^ 0xffffffff) < -1) {
|
||||
handledSounds[i_21_] = new int[i_22_];
|
||||
handledSounds[i_21_][0] = ByteBufferUtils.getMedium(buffer);
|
||||
for (int i_23_ = 1; ((i_22_ ^ 0xffffffff) < (i_23_ ^ 0xffffffff)); i_23_++) {
|
||||
handledSounds[i_21_][i_23_] = buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (opcode == 14) {
|
||||
aBoolean2141 = true;
|
||||
} else {
|
||||
System.out.println("Unhandled animation opcode " + opcode);
|
||||
}
|
||||
} else
|
||||
anInt2162 = buffer.get() & 0xFF;
|
||||
} else
|
||||
anInt2140 = buffer.get() & 0xFF;
|
||||
} else
|
||||
anInt2136 = buffer.get() & 0xFF;
|
||||
} else
|
||||
anInt2144 = buffer.getShort() & 0xFFFF;
|
||||
} else {
|
||||
aBooleanArray2149 = new boolean[256];
|
||||
int length = buffer.get() & 0xFF;
|
||||
for (int i = 0; i < length; i++) {
|
||||
aBooleanArray2149[buffer.get() & 0xFF] = true;
|
||||
}
|
||||
}
|
||||
} else
|
||||
anInt2163 = buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
|
||||
public void method2394() {
|
||||
if (anInt2140 == -1) {
|
||||
if (aBooleanArray2149 == null)
|
||||
anInt2140 = 0;
|
||||
else
|
||||
anInt2140 = 2;
|
||||
}
|
||||
if (anInt2162 == -1) {
|
||||
if (aBooleanArray2149 == null)
|
||||
anInt2162 = 0;
|
||||
else
|
||||
anInt2162 = 2;
|
||||
}
|
||||
}
|
||||
|
||||
public AnimationDefinition() {
|
||||
anInt2136 = 99;
|
||||
emoteItem = -1;
|
||||
anInt2140 = -1;
|
||||
aBoolean2152 = false;
|
||||
anInt2142 = 5;
|
||||
aBoolean2159 = false;
|
||||
anInt2163 = -1;
|
||||
anInt2155 = 2;
|
||||
aBoolean2158 = false;
|
||||
anInt2162 = -1;
|
||||
}
|
||||
}
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
package core.cache.def.impl;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import core.cache.Cache;
|
||||
import core.cache.misc.buffer.ByteBufferUtils;
|
||||
import core.game.world.GameWorld;
|
||||
|
||||
/**
|
||||
* The CS2 mapping.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class CS2Mapping {
|
||||
|
||||
/**
|
||||
* The CS2 mappings.
|
||||
*/
|
||||
private static final Map<Integer, CS2Mapping> maps = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The script id.
|
||||
*/
|
||||
private final int scriptId;
|
||||
|
||||
/**
|
||||
* Unknown value.
|
||||
*/
|
||||
private int unknown;
|
||||
|
||||
/**
|
||||
* Second unknown value.
|
||||
*/
|
||||
private int unknown1;
|
||||
|
||||
/**
|
||||
* The default string value.
|
||||
*/
|
||||
private String defaultString;
|
||||
|
||||
/**
|
||||
* The default integer value.
|
||||
*/
|
||||
private int defaultInt;
|
||||
|
||||
/**
|
||||
* The mapping.
|
||||
*/
|
||||
private HashMap<Integer, Object> map;
|
||||
|
||||
/**
|
||||
* The array of the objects.
|
||||
*/
|
||||
private Object[] array;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code CS2Mapping} {@code Object}.
|
||||
* @param scriptId The script id.
|
||||
*/
|
||||
public CS2Mapping(int scriptId) {
|
||||
this.scriptId = scriptId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
* @param args The arguments cast on runtime.
|
||||
* @throws Throwable When an exception occurs.
|
||||
*/
|
||||
public static void main(String... args) throws Throwable {
|
||||
GameWorld.prompt(false);
|
||||
BufferedWriter bw = Files.newBufferedWriter(Paths.get("./cs2.txt"));
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
CS2Mapping mapping = forId(i);
|
||||
if (mapping == null) {
|
||||
continue;
|
||||
}
|
||||
if (mapping.map == null) {
|
||||
continue;
|
||||
}
|
||||
bw.append("ScriptAPI - " + i + " [");
|
||||
for (int index : mapping.map.keySet()) {
|
||||
bw.append(mapping.map.get(index) + ": " + index + " ");
|
||||
}
|
||||
bw.append("]");
|
||||
bw.newLine();
|
||||
}
|
||||
bw.flush();
|
||||
bw.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mapping for the given script id.
|
||||
* @param scriptId The script id.
|
||||
* @return The mapping.
|
||||
*/
|
||||
public static CS2Mapping forId(int scriptId) {
|
||||
CS2Mapping mapping = maps.get(scriptId);
|
||||
if (mapping != null) {
|
||||
return mapping;
|
||||
}
|
||||
mapping = new CS2Mapping(scriptId);
|
||||
byte[] bs = Cache.getIndexes()[17].getFileData(scriptId >>> 8, scriptId & 0xFF);
|
||||
if (bs != null) {
|
||||
mapping.load(ByteBuffer.wrap(bs));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
maps.put(scriptId, mapping);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the mapping data.
|
||||
* @param buffer The buffer to read the data from.
|
||||
*/
|
||||
private void load(ByteBuffer buffer) {
|
||||
int opcode;
|
||||
while ((opcode = buffer.get() & 0xFF) != 0) {
|
||||
switch (opcode) {
|
||||
case 1:
|
||||
unknown = buffer.get() & 0xFF;
|
||||
break;
|
||||
case 2:
|
||||
unknown1 = buffer.get() & 0xFF;
|
||||
break;
|
||||
case 3:
|
||||
defaultString = ByteBufferUtils.getString(buffer);
|
||||
break;
|
||||
case 4:
|
||||
defaultInt = buffer.getInt();
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
int size = buffer.getShort() & 0xFFFF;
|
||||
String string = null;
|
||||
int val = 0;
|
||||
map = new HashMap<>(size);
|
||||
array = new Object[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
int key = buffer.getInt();
|
||||
if (opcode == 5) {
|
||||
string = ByteBufferUtils.getString(buffer);
|
||||
array[i] = string;
|
||||
map.put(key, string);
|
||||
} else {
|
||||
val = buffer.getInt();
|
||||
array[i] = val;
|
||||
map.put(key, val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the array of objects.
|
||||
* @return the objects.
|
||||
*/
|
||||
public Object[] getArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scriptId.
|
||||
* @return The scriptId.
|
||||
*/
|
||||
public int getScriptId() {
|
||||
return scriptId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unknown.
|
||||
* @return The unknown.
|
||||
*/
|
||||
public int getUnknown() {
|
||||
return unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unknown.
|
||||
* @param unknown The unknown to set.
|
||||
*/
|
||||
public void setUnknown(int unknown) {
|
||||
this.unknown = unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unknown1.
|
||||
* @return The unknown1.
|
||||
*/
|
||||
public int getUnknown1() {
|
||||
return unknown1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unknown1.
|
||||
* @param unknown1 The unknown1 to set.
|
||||
*/
|
||||
public void setUnknown1(int unknown1) {
|
||||
this.unknown1 = unknown1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the defaultString.
|
||||
* @return The defaultString.
|
||||
*/
|
||||
public String getDefaultString() {
|
||||
return defaultString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the defaultString.
|
||||
* @param defaultString The defaultString to set.
|
||||
*/
|
||||
public void setDefaultString(String defaultString) {
|
||||
this.defaultString = defaultString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the defaultInt.
|
||||
* @return The defaultInt.
|
||||
*/
|
||||
public int getDefaultInt() {
|
||||
return defaultInt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the defaultInt.
|
||||
* @param defaultInt The defaultInt to set.
|
||||
*/
|
||||
public void setDefaultInt(int defaultInt) {
|
||||
this.defaultInt = defaultInt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map.
|
||||
* @return The map.
|
||||
*/
|
||||
public HashMap<Integer, Object> getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the map.
|
||||
* @param map The map to set.
|
||||
*/
|
||||
public void setMap(HashMap<Integer, Object> map) {
|
||||
this.map = map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package core.cache.def.impl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import core.ServerConstants;
|
||||
import core.cache.Cache;
|
||||
|
||||
/**
|
||||
* The definitions for player clothing/look.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class ClothDefinition {
|
||||
|
||||
/**
|
||||
* The equipment slot.
|
||||
*/
|
||||
private int equipmentSlot;
|
||||
|
||||
/**
|
||||
* The model ids.
|
||||
*/
|
||||
private int[] modelIds;
|
||||
|
||||
/**
|
||||
* Unknown boolean.
|
||||
*/
|
||||
private boolean unknownBool;
|
||||
|
||||
/**
|
||||
* Original colors.
|
||||
*/
|
||||
private int[] originalColors;
|
||||
|
||||
/**
|
||||
* The colors to change to.
|
||||
*/
|
||||
private int[] modifiedColors;
|
||||
|
||||
/**
|
||||
* Original texture colors.
|
||||
*/
|
||||
private int[] originalTextureColors;
|
||||
|
||||
/**
|
||||
* Texture colors to change to.
|
||||
*/
|
||||
private int[] modifiedTextureColors;
|
||||
|
||||
/**
|
||||
* Other model ids(?)
|
||||
*/
|
||||
private int[] models = { -1, -1, -1, -1, -1 };
|
||||
|
||||
/**
|
||||
* Gets the definitions for the given cloth id.
|
||||
* @param clothId The clothing id.
|
||||
* @return The definition.
|
||||
*/
|
||||
public static ClothDefinition forId(int clothId) {
|
||||
ClothDefinition def = new ClothDefinition();
|
||||
byte[] bs = Cache.getIndexes()[2].getFileData(3, clothId);
|
||||
if (bs != null) {
|
||||
def.load(ByteBuffer.wrap(bs));
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
* @param args The arguments cast on runtime.
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
try {
|
||||
Cache.init(ServerConstants.CACHE_PATH);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
int length = Cache.getIndexes()[2].getFilesSize(3);
|
||||
System.out.println("Definition size: " + length + ".");
|
||||
for (int i = 0; i < length; i++) {
|
||||
ClothDefinition def = forId(i);
|
||||
if (def.unknownBool)
|
||||
System.out.println("Clothing " + i + ": " + def.equipmentSlot + ", " + def.unknownBool + ", " + Arrays.toString(def.modelIds) + ", " + Arrays.toString(def.models));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the definitions.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void load(ByteBuffer buffer) {
|
||||
int opcode;
|
||||
while ((opcode = buffer.get() & 0xFF) != 0) {
|
||||
parse(opcode, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an opcode.
|
||||
* @param opcode The opcode.
|
||||
* @param buffer The buffer to read the data from.
|
||||
*/
|
||||
private void parse(int opcode, ByteBuffer buffer) {
|
||||
switch (opcode) {
|
||||
case 1:
|
||||
equipmentSlot = buffer.get() & 0xFF;
|
||||
break;
|
||||
case 2:
|
||||
int length = buffer.get() & 0xFF;
|
||||
modelIds = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
modelIds[i] = buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
unknownBool = true;
|
||||
break;
|
||||
case 40:
|
||||
length = buffer.get() & 0xFF;
|
||||
originalColors = new int[length];
|
||||
modifiedColors = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
originalColors[i] = buffer.getShort();
|
||||
modifiedColors[i] = buffer.getShort();
|
||||
}
|
||||
break;
|
||||
case 41:
|
||||
length = buffer.get() & 0xFF;
|
||||
originalTextureColors = new int[length];
|
||||
modifiedTextureColors = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
originalTextureColors[i] = buffer.getShort();
|
||||
modifiedTextureColors[i] = buffer.getShort();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (opcode >= 60 && opcode < 70) {
|
||||
models[opcode - 60] = buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unknown.
|
||||
* @return The unknown.
|
||||
*/
|
||||
public int getUnknown() {
|
||||
return equipmentSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the modelIds.
|
||||
* @return The modelIds.
|
||||
*/
|
||||
public int[] getModelIds() {
|
||||
return modelIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unknownBool.
|
||||
* @return The unknownBool.
|
||||
*/
|
||||
public boolean isUnknownBool() {
|
||||
return unknownBool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the originalColors.
|
||||
* @return The originalColors.
|
||||
*/
|
||||
public int[] getOriginalColors() {
|
||||
return originalColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the modifiedColors.
|
||||
* @return The modifiedColors.
|
||||
*/
|
||||
public int[] getModifiedColors() {
|
||||
return modifiedColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the originalTextureColors.
|
||||
* @return The originalTextureColors.
|
||||
*/
|
||||
public int[] getOriginalTextureColors() {
|
||||
return originalTextureColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the modifiedTextureColors.
|
||||
* @return The modifiedTextureColors.
|
||||
*/
|
||||
public int[] getModifiedTextureColors() {
|
||||
return modifiedTextureColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the models.
|
||||
* @return The models.
|
||||
*/
|
||||
public int[] getModels() {
|
||||
return models;
|
||||
}
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package core.cache.def.impl;
|
||||
|
||||
import core.cache.Cache;
|
||||
import core.cache.misc.buffer.ByteBufferUtils;
|
||||
import core.tools.CP1252;
|
||||
import core.tools.SystemLogger;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DataMap {
|
||||
|
||||
/**
|
||||
* The config definitions mapping.
|
||||
*/
|
||||
private static final Map<Integer, core.cache.def.impl.DataMap> definitions = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The enum id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
public char keyType = '?';
|
||||
|
||||
public char valueType = '?';
|
||||
|
||||
public String defaultString;
|
||||
|
||||
public int defaultInt;
|
||||
|
||||
public HashMap<Integer, Object> dataStore = new HashMap<>();
|
||||
|
||||
public DataMap(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getInt(int key){
|
||||
if(!dataStore.containsKey(key)){
|
||||
SystemLogger.logErr(this.getClass(), "Invalid value passed for key: " + key + " map: " + id);
|
||||
return -1;
|
||||
}
|
||||
return (int) dataStore.get(key);
|
||||
}
|
||||
|
||||
public String getString(int key){
|
||||
return (String) dataStore.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
return "DataMapDefinition{" +
|
||||
"id=" + id +
|
||||
", keyType=" + keyType +
|
||||
", valueType=" + (valueType == 'K' ? "Normal" : valueType == 'J' ? "Struct Pointer" : "Unknown") +
|
||||
", defaultString='" + defaultString + '\'' +
|
||||
", defaultInt=" + defaultInt +
|
||||
", dataStore=" + dataStore +
|
||||
'}' + "\n";
|
||||
}
|
||||
|
||||
public static DataMap get(int id){
|
||||
core.cache.def.impl.DataMap def = definitions.get(id);
|
||||
if (def != null) {
|
||||
return def;
|
||||
}
|
||||
byte[] data = Cache.getIndexes()[17].getFileData(id >>> 8, id & 0xFF);
|
||||
def = parse(id, data);
|
||||
definitions.put(id, def);
|
||||
return def;
|
||||
}
|
||||
|
||||
public static DataMap parse(int id, byte[] data)
|
||||
{
|
||||
DataMap def = new DataMap(id);
|
||||
if (data != null) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||
int opcode;
|
||||
|
||||
while ((opcode = buffer.get() & 0xFF) != 0) {
|
||||
|
||||
if (opcode == 1) {
|
||||
def.keyType = CP1252.getFromByte(buffer.get());
|
||||
} else if (opcode == 2) {
|
||||
def.valueType = CP1252.getFromByte(buffer.get());
|
||||
} else if (opcode == 3) {
|
||||
def.defaultString = ByteBufferUtils.getString(buffer);
|
||||
} else if (opcode == 4) {
|
||||
def.defaultInt = buffer.getInt();
|
||||
} else if (opcode == 5 || opcode == 6) {
|
||||
int size = buffer.getShort() & 0xFFFF;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
int key = buffer.getInt();
|
||||
|
||||
Object value;
|
||||
if (opcode == 5) {
|
||||
value = ByteBufferUtils.getString(buffer);
|
||||
} else {
|
||||
value = buffer.getInt();
|
||||
}
|
||||
def.dataStore.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package core.cache.def.impl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import core.ServerConstants;
|
||||
import core.cache.Cache;
|
||||
|
||||
/**
|
||||
* Represents a Graphic's definition.
|
||||
* @author Jagex
|
||||
*/
|
||||
public class GraphicDefinition {
|
||||
|
||||
public short[] aShortArray1435;
|
||||
public short[] aShortArray1438;
|
||||
public int anInt1440;
|
||||
public boolean aBoolean1442;
|
||||
public int defaultModel;
|
||||
public int anInt1446;
|
||||
public boolean aBoolean1448 = false;
|
||||
public int anInt1449;
|
||||
public int animationId;
|
||||
public int anInt1451;
|
||||
public int graphicsId;
|
||||
public int anInt1454;
|
||||
public short[] aShortArray1455;
|
||||
public short[] aShortArray1456;
|
||||
|
||||
// added
|
||||
public byte byteValue;
|
||||
// added
|
||||
public int intValue;
|
||||
|
||||
/**
|
||||
* The definitions mapping.
|
||||
*/
|
||||
private static final Map<Integer, GraphicDefinition> graphicDefinitions = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Gets the graphic definition for the given graphic id.
|
||||
* @param gfxId The graphic id.
|
||||
* @return The definition.
|
||||
*/
|
||||
public static final GraphicDefinition forId(int gfxId) {
|
||||
GraphicDefinition def = graphicDefinitions.get(gfxId);
|
||||
if (def != null) {
|
||||
return def;
|
||||
}
|
||||
byte[] data = Cache.getIndexes()[21].getFileData(gfxId >>> 8, gfxId & 0xff);
|
||||
def = new GraphicDefinition();
|
||||
def.graphicsId = gfxId;
|
||||
if (data != null) {
|
||||
def.readValueLoop(ByteBuffer.wrap(data));
|
||||
}
|
||||
graphicDefinitions.put(gfxId, def);
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method, used for running a graphic definition search.
|
||||
* @param s The arguments cast on runtime.
|
||||
*/
|
||||
public static final void main(String... s) {
|
||||
try {
|
||||
Cache.init(ServerConstants.CACHE_PATH);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 5046 - 5050 are related anims & 2148
|
||||
GraphicDefinition d = GraphicDefinition.forId(803);
|
||||
System.out.println("Graphic " + d.graphicsId + " anim id = " + d.animationId + ", " + d.defaultModel + ".");
|
||||
for (int i = 0; i < 5000; i++) {
|
||||
GraphicDefinition def = GraphicDefinition.forId(i);
|
||||
if (def == null) {
|
||||
continue;
|
||||
}
|
||||
if ((def.animationId > 2000 && def.animationId < 2200) || (def.defaultModel >= 1300 && def.defaultModel < 1500)) {
|
||||
System.out.println("Possible match [id=" + i + ", anim=" + def.animationId + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and handles all data from the input stream.
|
||||
* @param buffer The input stream.
|
||||
*/
|
||||
private void readValueLoop(ByteBuffer buffer) {
|
||||
for (;;) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
if (opcode == 0) {
|
||||
break;
|
||||
}
|
||||
readValues(buffer, opcode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the opcode values from the input stream.
|
||||
* @param buffer The input stream.
|
||||
* @param opcode The opcode to handle.
|
||||
*/
|
||||
public void readValues(ByteBuffer buffer, int opcode) {
|
||||
if (opcode != 1) {
|
||||
if (opcode == 2)
|
||||
animationId = buffer.getShort();
|
||||
else if (opcode == 4)
|
||||
anInt1446 = buffer.getShort() & 0xFFFF;
|
||||
else if (opcode != 5) {
|
||||
if ((opcode ^ 0xffffffff) != -7) {
|
||||
if (opcode == 7)
|
||||
anInt1440 = buffer.get() & 0xFF;
|
||||
else if ((opcode ^ 0xffffffff) == -9)
|
||||
anInt1451 = buffer.get() & 0xFF;
|
||||
else if (opcode != 9) {
|
||||
if (opcode != 10) {
|
||||
if (opcode == 11) { // added opcode
|
||||
// aBoolean1442 = true;
|
||||
byteValue = (byte) 1;
|
||||
} else if (opcode == 12) { // added opcode
|
||||
// aBoolean1442 = true;
|
||||
byteValue = (byte) 4;
|
||||
} else if (opcode == 13) { // added opcode
|
||||
// aBoolean1442 = true;
|
||||
byteValue = (byte) 5;
|
||||
} else if (opcode == 14) { // added opcode
|
||||
// aBoolean1442 = true;
|
||||
// aByte2856 = 2;
|
||||
byteValue = (byte) 2;
|
||||
intValue = (buffer.get() & 0xFF) * 256;
|
||||
} else if (opcode == 15) {
|
||||
// aByte2856 = 3;
|
||||
byteValue = (byte) 3;
|
||||
intValue = buffer.getShort() & 0xFFFF;
|
||||
} else if (opcode == 16) {
|
||||
// aByte2856 = 3;
|
||||
byteValue = (byte) 3;
|
||||
intValue = buffer.getInt();
|
||||
} else if (opcode != 40) {
|
||||
if ((opcode ^ 0xffffffff) == -42) {
|
||||
int i = buffer.get() & 0xFF;
|
||||
aShortArray1455 = new short[i];
|
||||
aShortArray1435 = new short[i];
|
||||
for (int i_0_ = 0; i > i_0_; i_0_++) {
|
||||
aShortArray1455[i_0_] = (short) (buffer.getShort() & 0xFFFF);
|
||||
aShortArray1435[i_0_] = (short) (buffer.getShort() & 0xFFFF);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int i = buffer.get() & 0xFF;
|
||||
aShortArray1438 = new short[i];
|
||||
aShortArray1456 = new short[i];
|
||||
for (int i_1_ = 0; ((i ^ 0xffffffff) < (i_1_ ^ 0xffffffff)); i_1_++) {
|
||||
aShortArray1438[i_1_] = (short) (buffer.getShort() & 0xFFFF);
|
||||
aShortArray1456[i_1_] = (short) (buffer.getShort() & 0xFFFF);
|
||||
}
|
||||
}
|
||||
} else
|
||||
aBoolean1448 = true;
|
||||
} else {
|
||||
// aBoolean1442 = true;
|
||||
byteValue = (byte) 3;
|
||||
intValue = 8224;
|
||||
}
|
||||
} else
|
||||
anInt1454 = buffer.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt1449 = buffer.getShort() & 0xFFFF;
|
||||
} else
|
||||
defaultModel = buffer.getShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code GraphicDefinition} {@code Object}.
|
||||
*/
|
||||
public GraphicDefinition() {
|
||||
byteValue = 0;
|
||||
intValue = -1;
|
||||
anInt1446 = 128;
|
||||
aBoolean1442 = false;
|
||||
anInt1449 = 128;
|
||||
anInt1451 = 0;
|
||||
animationId = -1;
|
||||
anInt1454 = 0;
|
||||
anInt1440 = 0;
|
||||
}
|
||||
|
||||
}
|
||||
+1682
File diff suppressed because it is too large
Load Diff
+1117
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,328 @@
|
||||
package core.cache.def.impl;
|
||||
|
||||
import core.cache.Cache;
|
||||
import core.tools.SystemLogger;
|
||||
import core.game.world.GameWorld;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Holds definitions for render animations.
|
||||
* @author Jagex
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public class RenderAnimationDefinition {
|
||||
|
||||
public int turn180Animation;
|
||||
public int anInt951 = -1;
|
||||
public int anInt952;
|
||||
public int turnCWAnimation = -1;
|
||||
public int anInt954;
|
||||
public int anInt955;
|
||||
public int anInt956;
|
||||
public int anInt957;
|
||||
public int anInt958;
|
||||
public int[] anIntArray959 = null;
|
||||
public int anInt960;
|
||||
public int anInt961 = 0;
|
||||
public int anInt962;
|
||||
public int walkAnimationId;
|
||||
public int anInt964;
|
||||
public int anInt965;
|
||||
public int anInt966;
|
||||
public int[] standAnimationIds;
|
||||
public int anInt969;
|
||||
public int[] anIntArray971;
|
||||
public int standAnimationId;
|
||||
public int anInt973;
|
||||
public int anInt974;
|
||||
public int anInt975;
|
||||
public int runAnimationId;
|
||||
public int anInt977;
|
||||
public boolean aBoolean978;
|
||||
public int[][] anIntArrayArray979;
|
||||
public int anInt980;
|
||||
public int turnCCWAnimation;
|
||||
public int anInt983;
|
||||
public int anInt985;
|
||||
public int anInt986;
|
||||
public int anInt987;
|
||||
public int anInt988;
|
||||
public int anInt989;
|
||||
public int anInt990;
|
||||
public int anInt992;
|
||||
public int anInt993;
|
||||
public int anInt994;
|
||||
|
||||
/**
|
||||
* Gets the render animation definitions for the given id.
|
||||
* @param animId The render animation id.
|
||||
* @return The render animation definitions.
|
||||
*/
|
||||
public static RenderAnimationDefinition forId(int animId) {
|
||||
if (animId == -1) {
|
||||
return null;
|
||||
}
|
||||
byte[] data = Cache.getIndexes()[2].getFileData(32, animId);
|
||||
RenderAnimationDefinition defs = new RenderAnimationDefinition();
|
||||
if (data != null) {
|
||||
defs.parse(ByteBuffer.wrap(data));
|
||||
} else {
|
||||
SystemLogger.logErr(RenderAnimationDefinition.class, "No definitions found for render animation " + animId + ", size=" + Cache.getIndexes()[2].getFilesSize(32) + "!");
|
||||
}
|
||||
return defs;
|
||||
}
|
||||
|
||||
private void parse(ByteBuffer buffer) {
|
||||
for (;;) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
if (opcode == 0) {
|
||||
break;
|
||||
}
|
||||
parseOpcode(buffer, opcode);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseOpcode(ByteBuffer buffer, int opcode) {
|
||||
if (opcode == 54) {
|
||||
@SuppressWarnings("unused")
|
||||
int anInt1260 = (buffer.get() & 0xFF) << 6;
|
||||
@SuppressWarnings("unused")
|
||||
int anInt1227 = (buffer.get() & 0xFF) << 6;
|
||||
} else if (opcode == 55) {
|
||||
int[] anIntArray1246 = new int[12];
|
||||
int i_14_ = buffer.get() & 0xFF;
|
||||
anIntArray1246[i_14_] = buffer.getShort() & 0xFFFF;
|
||||
} else if (opcode == 56) {
|
||||
int[][] anIntArrayArray1217 = new int[12][];
|
||||
int i_12_ = buffer.get() & 0xFF;
|
||||
anIntArrayArray1217[i_12_] = new int[3];
|
||||
for (int i_13_ = 0; i_13_ < 3; i_13_++)
|
||||
anIntArrayArray1217[i_12_][i_13_] = buffer.getShort();
|
||||
} else if ((opcode ^ 0xffffffff) != -2) {
|
||||
if ((opcode ^ 0xffffffff) != -3) {
|
||||
if (opcode != 3) {
|
||||
if ((opcode ^ 0xffffffff) != -5) {
|
||||
if (opcode == 5)
|
||||
anInt977 = buffer.getShort() & 0xFFFF;
|
||||
else if ((opcode ^ 0xffffffff) != -7) {
|
||||
if (opcode == 7)
|
||||
anInt960 = buffer.getShort() & 0xFFFF;
|
||||
else if ((opcode ^ 0xffffffff) == -9)
|
||||
anInt985 = buffer.getShort() & 0xFFFF;
|
||||
else if (opcode == 9)
|
||||
anInt957 = buffer.getShort() & 0xFFFF;
|
||||
else if (opcode == 26) {
|
||||
anInt973 = (short) (4 * buffer
|
||||
.get() & 0xFF);
|
||||
anInt975 = (short) (buffer.get() & 0xFF * 4);
|
||||
} else if ((opcode ^ 0xffffffff) == -28) {
|
||||
if (anIntArrayArray979 == null)
|
||||
anIntArrayArray979 = new int[12][];
|
||||
int i = buffer.get() & 0xFF;
|
||||
anIntArrayArray979[i] = new int[6];
|
||||
for (int i_1_ = 0; (i_1_ ^ 0xffffffff) > -7; i_1_++)
|
||||
anIntArrayArray979[i][i_1_] = buffer
|
||||
.getShort();
|
||||
} else if ((opcode ^ 0xffffffff) == -29) {
|
||||
anIntArray971 = new int[12];
|
||||
for (int i = 0; i < 12; i++) {
|
||||
anIntArray971[i] = buffer
|
||||
.get() & 0xFF;
|
||||
if (anIntArray971[i] == 255)
|
||||
anIntArray971[i] = -1;
|
||||
}
|
||||
} else if (opcode != 29) {
|
||||
if (opcode != 30) {
|
||||
if ((opcode ^ 0xffffffff) != -32) {
|
||||
if (opcode != 32) {
|
||||
if ((opcode ^ 0xffffffff) != -34) {
|
||||
if (opcode != 34) {
|
||||
if (opcode != 35) {
|
||||
if ((opcode ^ 0xffffffff) != -37) {
|
||||
if ((opcode ^ 0xffffffff) != -38) {
|
||||
if (opcode != 38) {
|
||||
if ((opcode ^ 0xffffffff) != -40) {
|
||||
if ((opcode ^ 0xffffffff) != -41) {
|
||||
if ((opcode ^ 0xffffffff) == -42)
|
||||
turnCWAnimation = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
else if (opcode != 42) {
|
||||
if ((opcode ^ 0xffffffff) == -44)
|
||||
buffer.getShort();
|
||||
else if ((opcode ^ 0xffffffff) != -45) {
|
||||
if ((opcode ^ 0xffffffff) == -46)
|
||||
anInt964 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
else if ((opcode ^ 0xffffffff) != -47) {
|
||||
if (opcode == 47)
|
||||
anInt966 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
else if (opcode == 48)
|
||||
anInt989 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
else if (opcode != 49) {
|
||||
if ((opcode ^ 0xffffffff) != -51) {
|
||||
if (opcode != 51) {
|
||||
if (opcode == 52) {
|
||||
int i = buffer
|
||||
.get() & 0xFF;
|
||||
anIntArray959 = new int[i];
|
||||
standAnimationIds = new int[i];
|
||||
for (int i_2_ = 0; i_2_ < i; i_2_++) {
|
||||
standAnimationIds[i_2_] = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
int i_3_ = buffer
|
||||
.get() & 0xFF;
|
||||
anIntArray959[i_2_] = i_3_;
|
||||
anInt994 += i_3_;
|
||||
}
|
||||
} else if (opcode == 53)
|
||||
aBoolean978 = false;
|
||||
} else
|
||||
anInt962 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt990 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt952 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt983 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt955 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
turnCCWAnimation = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
turn180Animation = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt954 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt958 = (buffer
|
||||
.getShort() & 0xFFFF);
|
||||
} else
|
||||
anInt951 = (buffer
|
||||
.get() & 0xFF);
|
||||
} else
|
||||
anInt965 = (buffer
|
||||
.getShort());
|
||||
} else
|
||||
anInt969 = (buffer
|
||||
.getShort() & 0xFFFF);
|
||||
} else
|
||||
anInt993 = buffer
|
||||
.get() & 0xFF;
|
||||
} else
|
||||
anInt956 = (buffer.getShort());
|
||||
} else
|
||||
anInt961 = buffer
|
||||
.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt988 = buffer.get() & 0xFF;
|
||||
} else
|
||||
anInt980 = buffer.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt992 = buffer.get() & 0xFF;
|
||||
} else
|
||||
runAnimationId = buffer.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt986 = buffer.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt987 = buffer.getShort() & 0xFFFF;
|
||||
} else
|
||||
anInt974 = buffer.getShort() & 0xFFFF;
|
||||
} else {
|
||||
standAnimationId = buffer.getShort() & 0xFFFF;
|
||||
walkAnimationId = buffer.getShort() & 0xFFFF;
|
||||
if ((standAnimationId ^ 0xffffffff) == -65536)
|
||||
standAnimationId = -1;
|
||||
if ((walkAnimationId ^ 0xffffffff) == -65536)
|
||||
walkAnimationId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public RenderAnimationDefinition() {
|
||||
anInt957 = -1;
|
||||
anInt954 = -1;
|
||||
anInt960 = -1;
|
||||
anInt958 = -1;
|
||||
anInt965 = 0;
|
||||
anInt973 = 0;
|
||||
turn180Animation = -1;
|
||||
anInt956 = 0;
|
||||
standAnimationId = -1;
|
||||
standAnimationIds = null;
|
||||
anInt952 = -1;
|
||||
anInt983 = -1;
|
||||
anInt985 = -1;
|
||||
anInt962 = -1;
|
||||
anInt966 = -1;
|
||||
anInt977 = -1;
|
||||
anInt975 = 0;
|
||||
runAnimationId = -1;
|
||||
anInt988 = 0;
|
||||
turnCCWAnimation = -1;
|
||||
anInt987 = -1;
|
||||
anInt980 = 0;
|
||||
anInt964 = -1;
|
||||
walkAnimationId = -1;
|
||||
anInt986 = -1;
|
||||
aBoolean978 = true;
|
||||
anInt992 = 0;
|
||||
anInt955 = -1;
|
||||
anInt989 = -1;
|
||||
anInt974 = -1;
|
||||
anInt969 = 0;
|
||||
anInt994 = 0;
|
||||
anInt990 = -1;
|
||||
anInt993 = 0;
|
||||
}
|
||||
|
||||
public static void main(String...args) throws Throwable {
|
||||
GameWorld.prompt(false);
|
||||
RenderAnimationDefinition def = RenderAnimationDefinition.forId(1426);
|
||||
System.out.println("size: " + def.getClass().getDeclaredFields().length);
|
||||
for (Field f : def.getClass().getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(f.getModifiers())) {
|
||||
if (f.getType().isArray()) {
|
||||
Object object = f.get(def);
|
||||
if (object != null) {
|
||||
int length = Array.getLength(object);
|
||||
System.out.print(f.getName() + ", [");
|
||||
for (int i = 0; i < length; i++) {
|
||||
System.out.print(Array.get(object, i) + (i < (length - 1) ? ", " : "]"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
System.out.println(f.getName() + ", " + f.get(def));
|
||||
}
|
||||
}
|
||||
for (Field f : def.getClass().getSuperclass().getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(f.getModifiers())) {
|
||||
if (f.getType().isArray()) {
|
||||
Object object = f.get(def);
|
||||
if (object != null) {
|
||||
int length = Array.getLength(object);
|
||||
System.out.print(f.getName() + ", [");
|
||||
for (int i = 0; i < length; i++) {
|
||||
System.out.print(Array.get(object, i) + (i < (length - 1) ? ", " : "]"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
System.out.println(f.getName() + ", " + f.get(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+97
@@ -0,0 +1,97 @@
|
||||
package core.cache.def.impl;
|
||||
|
||||
import core.cache.Cache;
|
||||
import core.cache.misc.buffer.ByteBufferUtils;
|
||||
import core.tools.SystemLogger;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Struct {
|
||||
|
||||
/**
|
||||
* The struct definitions mapping.
|
||||
*/
|
||||
private static final Map<Integer, Struct> definitions = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The enum id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
public HashMap<Integer, Object> dataStore = new HashMap<>();
|
||||
|
||||
public Struct(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getInt(int key){
|
||||
if(!dataStore.containsKey(key)){
|
||||
SystemLogger.logErr(this.getClass(), "Invalid value passed for key: " + key + " struct: " + id);
|
||||
return -1;
|
||||
}
|
||||
return (int) dataStore.get(key);
|
||||
}
|
||||
|
||||
public String getString(int key){
|
||||
return (String) dataStore.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Struct{" +
|
||||
"id=" + id +
|
||||
", dataStore=" + dataStore +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static Struct get(int id){
|
||||
Struct def = definitions.get(id);
|
||||
if (def != null) {
|
||||
return def;
|
||||
}
|
||||
byte[] data = Cache.getIndexes()[2].getFileData(26, id);
|
||||
def = parse(id, data);
|
||||
|
||||
definitions.put(id, def);
|
||||
return def;
|
||||
}
|
||||
|
||||
public static Struct parse(int id, byte[] data)
|
||||
{
|
||||
Struct def = new Struct(id);
|
||||
if (data != null) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||
int opcode;
|
||||
|
||||
while ((opcode = buffer.get() & 0xFF) != 0) {
|
||||
|
||||
if (opcode == 249) {
|
||||
int size = buffer.get() & 0xFF;
|
||||
|
||||
for (int i = 0; size > i; i++) {
|
||||
boolean bool = (buffer.get() & 0xFF) == 1;
|
||||
int key = ByteBufferUtils.getMedium(buffer);
|
||||
Object value;
|
||||
if (bool) {
|
||||
value = ByteBufferUtils.getString(buffer);
|
||||
} else {
|
||||
value = buffer.getInt();
|
||||
}
|
||||
def.dataStore.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
public static int getCount() {
|
||||
return Cache.getIndexes()[2].getFilesSize(26);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package core.cache.def.impl;
|
||||
|
||||
import core.cache.Cache;
|
||||
import core.game.node.entity.player.Player;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Handles config definition reading.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class VarbitDefinition {
|
||||
|
||||
/**
|
||||
* The config definitions mapping.
|
||||
*/
|
||||
private static final Map<Integer, VarbitDefinition> MAPPING = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The bit size flags.
|
||||
*/
|
||||
private static final int[] BITS = new int[32];
|
||||
|
||||
/**
|
||||
* The file id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* The config id.
|
||||
*/
|
||||
private int varpId;
|
||||
|
||||
/**
|
||||
* The bit shift amount.
|
||||
*/
|
||||
private int startBit;
|
||||
|
||||
/**
|
||||
* The bit amount.
|
||||
*/
|
||||
private int endBit;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ConfigFileDefinition} {@code Object}.
|
||||
* @param id The file id.
|
||||
*/
|
||||
public VarbitDefinition(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public VarbitDefinition(int varpId, int id, int startBit, int endBit)
|
||||
{
|
||||
this.varpId = varpId;
|
||||
this.id = id;
|
||||
this.startBit = startBit;
|
||||
this.endBit = endBit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the bit flags.
|
||||
*/
|
||||
static {
|
||||
int flag = 2;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
BITS[i] = flag - 1;
|
||||
flag += flag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the config file definitions for the given file id.
|
||||
* @param id The file id.
|
||||
* @return The definition.
|
||||
*/
|
||||
public static VarbitDefinition forObjectID(int id) {
|
||||
return forId(id);
|
||||
}
|
||||
|
||||
public static VarbitDefinition forNPCID(int id){
|
||||
return forId(id);
|
||||
}
|
||||
|
||||
public static VarbitDefinition forItemID(int id){
|
||||
return forId(id);
|
||||
}
|
||||
|
||||
public static VarbitDefinition forId(int id){
|
||||
VarbitDefinition def = MAPPING.get(id);
|
||||
if (def != null) {
|
||||
return def;
|
||||
}
|
||||
|
||||
def = new VarbitDefinition(id);
|
||||
byte[] bs = Cache.getIndexes()[22].getFileData(id >>> 10, id & 0x3ff);
|
||||
if (bs != null) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bs);
|
||||
int opcode = 0;
|
||||
while ((opcode = buffer.get() & 0xFF) != 0) {
|
||||
if (opcode == 1) {
|
||||
def.varpId = buffer.getShort() & 0xFFFF;
|
||||
def.startBit = buffer.get() & 0xFF;
|
||||
def.endBit = buffer.get() & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
MAPPING.put(id, def);
|
||||
return def;
|
||||
}
|
||||
|
||||
public static void create(int varpId, int varbitId, int startBit, int endBit){
|
||||
VarbitDefinition def = new VarbitDefinition(
|
||||
varpId,
|
||||
varbitId,
|
||||
startBit,
|
||||
endBit
|
||||
);
|
||||
MAPPING.put(varbitId, def);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current config value for this file.
|
||||
* @param player The player.
|
||||
* @return The config value.
|
||||
*/
|
||||
public int getValue(Player player) {
|
||||
int size = BITS[endBit - startBit];
|
||||
int bitValue = player.varpManager.get(getVarpId()).getBitRangeValue(getStartBit(), getStartBit() + (endBit - startBit));
|
||||
if(bitValue != 0){
|
||||
return size & (bitValue >>> startBit);
|
||||
}
|
||||
return size & (player.getConfigManager().get(varpId) >>> startBit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mapping.
|
||||
* @return The mapping.
|
||||
*/
|
||||
public static Map<Integer, VarbitDefinition> getMapping() {
|
||||
return MAPPING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id.
|
||||
* @return The id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getVarpId() {
|
||||
return varpId;
|
||||
}
|
||||
|
||||
public int getStartBit() {
|
||||
return startBit;
|
||||
}
|
||||
|
||||
public int getEndBit() {
|
||||
return endBit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConfigFileDefinition [id=" + id + ", configId=" + varpId + ", bitShift=" + startBit + ", bitSize=" + endBit + "]";
|
||||
}
|
||||
}
|
||||
+365
@@ -0,0 +1,365 @@
|
||||
private void readValues(int i, InputStream stream, int opcode) {
|
||||
if (opcode != 1 && opcode != 5) {
|
||||
if (opcode != 2) {
|
||||
if (opcode != 14) {
|
||||
if (opcode != 15) {
|
||||
if (opcode == 17) {
|
||||
projectileCliped = false;
|
||||
clipType = 0;
|
||||
} else if (opcode != 18) {
|
||||
if (opcode == 19)
|
||||
secondInt = stream.readUnsignedByte();
|
||||
else if (opcode == 21)
|
||||
aByte3912 = (byte) 1;
|
||||
else if (opcode != 22) {
|
||||
if (opcode != 23) {
|
||||
if (opcode != 24) {
|
||||
if (opcode == 27)
|
||||
clipType = 1;
|
||||
else if (opcode == 28)
|
||||
anInt3892 = (stream
|
||||
.readUnsignedByte() << 2);
|
||||
else if (opcode != 29) {
|
||||
if (opcode != 39) {
|
||||
if (opcode < 30 || opcode >= 35) {
|
||||
if (opcode == 40) {
|
||||
int i_53_ = (stream
|
||||
.readUnsignedByte());
|
||||
originalColors = new short[i_53_];
|
||||
modifiedColors = new short[i_53_];
|
||||
for (int i_54_ = 0; i_53_ > i_54_; i_54_++) {
|
||||
originalColors[i_54_] = (short) (stream
|
||||
.readUnsignedShort());
|
||||
modifiedColors[i_54_] = (short) (stream
|
||||
.readUnsignedShort());
|
||||
}
|
||||
} else if (opcode != 41) {
|
||||
if (opcode != 42) {
|
||||
if (opcode != 62) {
|
||||
if (opcode != 64) {
|
||||
if (opcode == 65)
|
||||
anInt3902 = stream
|
||||
.readUnsignedShort();
|
||||
else if (opcode != 66) {
|
||||
if (opcode != 67) {
|
||||
if (opcode == 69)
|
||||
anInt3925 = stream
|
||||
.readUnsignedByte();
|
||||
else if (opcode != 70) {
|
||||
if (opcode == 71)
|
||||
anInt3889 = stream
|
||||
.readShort() << 2;
|
||||
else if (opcode != 72) {
|
||||
if (opcode == 73)
|
||||
secondBool = true;
|
||||
else if (opcode == 74)
|
||||
notCliped = true;
|
||||
else if (opcode != 75) {
|
||||
if (opcode != 77
|
||||
&& opcode != 92) {
|
||||
if (opcode == 78) {
|
||||
anInt3860 = stream
|
||||
.readUnsignedShort();
|
||||
anInt3904 = stream
|
||||
.readUnsignedByte();
|
||||
} else if (opcode != 79) {
|
||||
if (opcode == 81) {
|
||||
aByte3912 = (byte) 2;
|
||||
anInt3882 = 256 * stream
|
||||
.readUnsignedByte();
|
||||
} else if (opcode != 82) {
|
||||
if (opcode == 88)
|
||||
aBoolean3853 = false;
|
||||
else if (opcode != 89) {
|
||||
if (opcode == 90)
|
||||
aBoolean3870 = true;
|
||||
else if (opcode != 91) {
|
||||
if (opcode != 93) {
|
||||
if (opcode == 94)
|
||||
aByte3912 = (byte) 4;
|
||||
else if (opcode != 95) {
|
||||
if (opcode != 96) {
|
||||
if (opcode == 97)
|
||||
aBoolean3866 = true;
|
||||
else if (opcode == 98)
|
||||
aBoolean3923 = true;
|
||||
else if (opcode == 99) {
|
||||
anInt3857 = stream
|
||||
.readUnsignedByte();
|
||||
anInt3835 = stream
|
||||
.readUnsignedShort();
|
||||
} else if (opcode == 100) {
|
||||
anInt3844 = stream
|
||||
.readUnsignedByte();
|
||||
anInt3913 = stream
|
||||
.readUnsignedShort();
|
||||
} else if (opcode != 101) {
|
||||
if (opcode == 102)
|
||||
anInt3838 = stream
|
||||
.readUnsignedShort();
|
||||
else if (opcode == 103)
|
||||
thirdInt = 0;
|
||||
else if (opcode != 104) {
|
||||
if (opcode == 105)
|
||||
aBoolean3906 = true;
|
||||
else if (opcode == 106) {
|
||||
int i_55_ = stream
|
||||
.readUnsignedByte();
|
||||
anIntArray3869 = new int[i_55_];
|
||||
anIntArray3833 = new int[i_55_];
|
||||
for (int i_56_ = 0; i_56_ < i_55_; i_56_++) {
|
||||
anIntArray3833[i_56_] = stream
|
||||
.readUnsignedShort();
|
||||
int i_57_ = stream
|
||||
.readUnsignedByte();
|
||||
anIntArray3869[i_56_] = i_57_;
|
||||
anInt3881 += i_57_;
|
||||
}
|
||||
} else if (opcode == 107)
|
||||
anInt3851 = stream
|
||||
.readUnsignedShort();
|
||||
else if (opcode >= 150
|
||||
&& opcode < 155) {
|
||||
options[opcode
|
||||
+ -150] = stream
|
||||
.readString();
|
||||
/*if (!loader.showOptions)
|
||||
options[opcode + -150] = null;*/
|
||||
} else if (opcode != 160) {
|
||||
if (opcode == 162) {
|
||||
aByte3912 = (byte) 3;
|
||||
anInt3882 = stream
|
||||
.readInt();
|
||||
} else if (opcode == 163) {
|
||||
aByte3847 = (byte) stream
|
||||
.readByte();
|
||||
aByte3849 = (byte) stream
|
||||
.readByte();
|
||||
aByte3837 = (byte) stream
|
||||
.readByte();
|
||||
aByte3914 = (byte) stream
|
||||
.readByte();
|
||||
} else if (opcode != 164) {
|
||||
if (opcode != 165) {
|
||||
if (opcode != 166) {
|
||||
if (opcode == 167)
|
||||
anInt3921 = stream
|
||||
.readUnsignedShort();
|
||||
else if (opcode != 168) {
|
||||
if (opcode == 169) {
|
||||
aBoolean3845 = true;
|
||||
//added opcode
|
||||
}else if (opcode == 170) {
|
||||
int anInt3383 = stream.readUnsignedSmart();
|
||||
//added opcode
|
||||
}else if (opcode == 171) {
|
||||
int anInt3362 = stream.readUnsignedSmart();
|
||||
//added opcode
|
||||
}else if (opcode == 173) {
|
||||
int anInt3302 = stream.readUnsignedShort();
|
||||
int anInt3336 = stream.readUnsignedShort();
|
||||
//added opcode
|
||||
}else if (opcode == 177) {
|
||||
boolean ub = true;
|
||||
//added opcode
|
||||
}else if (opcode == 178) {
|
||||
int db = stream.readUnsignedByte();
|
||||
} else if (opcode == 249) {
|
||||
int i_58_ = stream
|
||||
.readUnsignedByte();
|
||||
if (aClass194_3922 == null) {
|
||||
/*int i_59_ = Class307
|
||||
.method3331(
|
||||
(byte) -117,
|
||||
i_58_);
|
||||
aClass194_3922 = new HashTable(
|
||||
i_59_);*/
|
||||
}
|
||||
for (int i_60_ = 0; i_60_ < i_58_; i_60_++) {
|
||||
boolean bool = stream
|
||||
.readUnsignedByte() == 1;
|
||||
int i_61_ = stream.read24BitInt();
|
||||
Object class279;
|
||||
if (!bool)
|
||||
/*class279 = new IntegerNode(*/
|
||||
stream
|
||||
.readInt();//);
|
||||
else
|
||||
/*class279 = new Class279_Sub4(*/
|
||||
stream
|
||||
.readString();//);
|
||||
/*aClass194_3922
|
||||
.method1598(
|
||||
(long) i_61_,
|
||||
-125,
|
||||
class279);*/
|
||||
}
|
||||
}
|
||||
} else
|
||||
aBoolean3894 = true;
|
||||
} else
|
||||
anInt3877 = stream
|
||||
.readShort();
|
||||
} else
|
||||
anInt3875 = stream
|
||||
.readShort();
|
||||
} else
|
||||
anInt3834 = stream
|
||||
.readShort();
|
||||
} else {
|
||||
int i_62_ = stream
|
||||
.readUnsignedByte();
|
||||
anIntArray3908 = new int[i_62_];
|
||||
for (int i_63_ = 0; i_62_ > i_63_; i_63_++)
|
||||
anIntArray3908[i_63_] = stream
|
||||
.readUnsignedShort();
|
||||
}
|
||||
} else
|
||||
anInt3865 = stream
|
||||
.readUnsignedByte();
|
||||
} else
|
||||
anInt3850 = stream
|
||||
.readUnsignedByte();
|
||||
} else
|
||||
aBoolean3924 = true;
|
||||
} else {
|
||||
aByte3912 = (byte) 5;
|
||||
anInt3882 = stream
|
||||
.readShort();
|
||||
}
|
||||
} else {
|
||||
aByte3912 = (byte) 3;
|
||||
anInt3882 = stream
|
||||
.readUnsignedShort();
|
||||
}
|
||||
} else
|
||||
aBoolean3873 = true;
|
||||
} else
|
||||
aBoolean3895 = false;
|
||||
} else
|
||||
aBoolean3891 = true;
|
||||
} else {
|
||||
anInt3900 = stream
|
||||
.readUnsignedShort();
|
||||
anInt3905 = stream
|
||||
.readUnsignedShort();
|
||||
anInt3904 = stream
|
||||
.readUnsignedByte();
|
||||
int i_64_ = stream
|
||||
.readUnsignedByte();
|
||||
anIntArray3859 = new int[i_64_];
|
||||
for (int i_65_ = 0; i_65_ < i_64_; i_65_++)
|
||||
anIntArray3859[i_65_] = stream
|
||||
.readUnsignedShort();
|
||||
}
|
||||
} else {
|
||||
configFileId = stream
|
||||
.readUnsignedShort();
|
||||
if (configFileId == 65535)
|
||||
configFileId = -1;
|
||||
configId = stream
|
||||
.readUnsignedShort();
|
||||
if (configId == 65535)
|
||||
configId = -1;
|
||||
int i_66_ = -1;
|
||||
if (opcode == 92) {
|
||||
i_66_ = stream
|
||||
.readUnsignedShort();
|
||||
if (i_66_ == 65535)
|
||||
i_66_ = -1;
|
||||
}
|
||||
int i_67_ = stream
|
||||
.readUnsignedByte();
|
||||
childrenIds = new int[i_67_
|
||||
- -2];
|
||||
for (int i_68_ = 0; i_67_ >= i_68_; i_68_++) {
|
||||
childrenIds[i_68_] = stream
|
||||
.readUnsignedShort();
|
||||
if (childrenIds[i_68_] == 65535)
|
||||
childrenIds[i_68_] = -1;
|
||||
}
|
||||
childrenIds[i_67_ + 1] = i_66_;
|
||||
}
|
||||
} else
|
||||
anInt3855 = stream
|
||||
.readUnsignedByte();
|
||||
} else
|
||||
anInt3915 = stream
|
||||
.readShort() << 2;
|
||||
} else
|
||||
anInt3883 = stream
|
||||
.readShort() << 2;
|
||||
} else
|
||||
anInt3917 = stream
|
||||
.readUnsignedShort();
|
||||
} else
|
||||
anInt3841 = stream
|
||||
.readUnsignedShort();
|
||||
} else
|
||||
aBoolean3872 = false;
|
||||
} else
|
||||
aBoolean3839 = true;
|
||||
} else {
|
||||
int i_69_ = (stream
|
||||
.readUnsignedByte());
|
||||
aByteArray3858 = (new byte[i_69_]);
|
||||
for (int i_70_ = 0; i_70_ < i_69_; i_70_++)
|
||||
aByteArray3858[i_70_] = (byte) (stream
|
||||
.readByte());
|
||||
}
|
||||
} else {
|
||||
int i_71_ = (stream
|
||||
.readUnsignedByte());
|
||||
aShortArray3920 = new short[i_71_];
|
||||
aShortArray3919 = new short[i_71_];
|
||||
for (int i_72_ = 0; i_71_ > i_72_; i_72_++) {
|
||||
aShortArray3920[i_72_] = (short) (stream
|
||||
.readUnsignedShort());
|
||||
aShortArray3919[i_72_] = (short) (stream
|
||||
.readUnsignedShort());
|
||||
}
|
||||
}
|
||||
} else
|
||||
options[-30
|
||||
+ opcode] = (stream
|
||||
.readString());
|
||||
} else
|
||||
anInt3840 = (stream.readByte() * 5);
|
||||
} else
|
||||
anInt3878 = stream.readByte();
|
||||
} else {
|
||||
anInt3876 = stream.readUnsignedShort();
|
||||
if (anInt3876 == 65535)
|
||||
anInt3876 = -1;
|
||||
}
|
||||
} else
|
||||
thirdInt = 1;
|
||||
} else
|
||||
aBoolean3867 = true;
|
||||
} else
|
||||
projectileCliped = false;
|
||||
} else
|
||||
sizeY = stream.readUnsignedByte();
|
||||
} else
|
||||
sizeX = stream.readUnsignedByte();
|
||||
} else
|
||||
name = stream.readString();
|
||||
} else {
|
||||
boolean aBoolean1162 = false;
|
||||
if (opcode == 5 && aBoolean1162)
|
||||
method3297(stream);
|
||||
int i_73_ = stream.readUnsignedByte();
|
||||
anIntArrayArray3916 = new int[i_73_][];
|
||||
aByteArray3899 = new byte[i_73_];
|
||||
for (int i_74_ = 0; i_74_ < i_73_; i_74_++) {
|
||||
aByteArray3899[i_74_] = (byte) stream.readByte();
|
||||
int i_75_ = stream.readUnsignedByte();
|
||||
anIntArrayArray3916[i_74_] = new int[i_75_];
|
||||
for (int i_76_ = 0; i_75_ > i_76_; i_76_++)
|
||||
anIntArrayArray3916[i_74_][i_76_] = stream
|
||||
.readUnsignedShort();
|
||||
}
|
||||
if (opcode == 5 && !aBoolean1162)
|
||||
method3297(stream);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package core.cache.gzip;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.zip.Inflater;
|
||||
|
||||
public class GZipDecompressor {
|
||||
|
||||
private static final Inflater inflaterInstance = new Inflater(true);
|
||||
|
||||
public static final void decompress(ByteBuffer buffer, byte[] data) {
|
||||
synchronized (inflaterInstance) {
|
||||
if (~buffer.get(buffer.position()) != -32 || buffer.get(buffer.position() + 1) != -117) {
|
||||
data = null;
|
||||
// throw new RuntimeException("Invalid GZIP header!");
|
||||
}
|
||||
try {
|
||||
inflaterInstance.setInput(buffer.array(), buffer.position() + 10, -buffer.position() - 18 + buffer.limit());
|
||||
inflaterInstance.inflate(data);
|
||||
} catch (Exception e) {
|
||||
// inflaterInstance.reset();
|
||||
data = null;
|
||||
// throw new RuntimeException("Invalid GZIP compressed data!");
|
||||
}
|
||||
inflaterInstance.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean decompress(byte[] compressed, byte data[], int offset, int length) {
|
||||
synchronized (inflaterInstance) {
|
||||
if (data[offset] != 31 || data[offset + 1] != -117)
|
||||
return false;
|
||||
// throw new RuntimeException("Invalid GZIP header!");
|
||||
try {
|
||||
inflaterInstance.setInput(data, offset + 10, -offset - 18 + length);
|
||||
inflaterInstance.inflate(compressed);
|
||||
} catch (Exception e) {
|
||||
inflaterInstance.reset();
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
// throw new RuntimeException("Invalid GZIP compressed data!");
|
||||
}
|
||||
inflaterInstance.reset();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package core.cache.misc;
|
||||
|
||||
/**
|
||||
* A container.
|
||||
* @author Dragonkk
|
||||
*/
|
||||
public class Container {
|
||||
|
||||
/**
|
||||
* The version.
|
||||
*/
|
||||
private int version;
|
||||
|
||||
/**
|
||||
* The CRC.
|
||||
*/
|
||||
private int crc;
|
||||
|
||||
/**
|
||||
* The name hash.
|
||||
*/
|
||||
private int nameHash;
|
||||
|
||||
/**
|
||||
* If updated.
|
||||
*/
|
||||
private boolean updated;
|
||||
|
||||
/**
|
||||
* Construct a new container.
|
||||
*/
|
||||
public Container() {
|
||||
nameHash = -1;
|
||||
version = -1;
|
||||
crc = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the version.
|
||||
* @param version
|
||||
*/
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the version.
|
||||
*/
|
||||
public void updateVersion() {
|
||||
version++;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version.
|
||||
* @return The version.
|
||||
*/
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next version.
|
||||
* @return The next version.
|
||||
*/
|
||||
public int getNextVersion() {
|
||||
return updated ? version : version + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CRC.
|
||||
* @param crc The cRC.
|
||||
*/
|
||||
public void setCrc(int crc) {
|
||||
this.crc = crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CRC.
|
||||
* @return The CRC.
|
||||
*/
|
||||
public int getCrc() {
|
||||
return crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name hash.
|
||||
* @param nameHash The name hash.
|
||||
*/
|
||||
public void setNameHash(int nameHash) {
|
||||
this.nameHash = nameHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name hash.
|
||||
* @return The name hash.
|
||||
*/
|
||||
public int getNameHash() {
|
||||
return nameHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* If is updated.
|
||||
* @return If is updated.
|
||||
*/
|
||||
public boolean isUpdated() {
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
package core.cache.misc;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import core.cache.bzip2.BZip2Decompressor;
|
||||
import core.cache.gzip.GZipDecompressor;
|
||||
|
||||
/**
|
||||
* A class holding the containers information.
|
||||
* @author Dragonkk
|
||||
*/
|
||||
public final class ContainersInformation {
|
||||
|
||||
/**
|
||||
* The information container.
|
||||
*/
|
||||
private Container informationContainer;
|
||||
|
||||
/**
|
||||
* The protocol.
|
||||
*/
|
||||
private int protocol;
|
||||
|
||||
/**
|
||||
* The revision.
|
||||
*/
|
||||
private int revision;
|
||||
|
||||
/**
|
||||
* The container indexes.
|
||||
*/
|
||||
private int[] containersIndexes;
|
||||
|
||||
/**
|
||||
* The containers.
|
||||
*/
|
||||
private FilesContainer[] containers;
|
||||
|
||||
/**
|
||||
* If files have to be named.
|
||||
*/
|
||||
private boolean filesNamed;
|
||||
|
||||
/**
|
||||
* If it has to be whirpool.
|
||||
*/
|
||||
private boolean whirpool;
|
||||
|
||||
/**
|
||||
* The data.
|
||||
*/
|
||||
private final byte[] data;
|
||||
|
||||
/**
|
||||
* Construct a new containers information.
|
||||
* @param informationContainerPackedData The information container data
|
||||
* packed.
|
||||
*/
|
||||
public ContainersInformation(byte[] informationContainerPackedData) {
|
||||
this.data = Arrays.copyOf(informationContainerPackedData, informationContainerPackedData.length);
|
||||
informationContainer = new Container();
|
||||
informationContainer.setVersion((informationContainerPackedData[informationContainerPackedData.length - 2] << 8 & 0xff00) + (informationContainerPackedData[-1 + informationContainerPackedData.length] & 0xff));
|
||||
CRC32 crc32 = new CRC32();
|
||||
crc32.update(informationContainerPackedData);
|
||||
informationContainer.setCrc((int) crc32.getValue());
|
||||
decodeContainersInformation(unpackCacheContainer(informationContainerPackedData));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks a container.
|
||||
* @param packedData The packed container data.
|
||||
* @return The unpacked data.
|
||||
*/
|
||||
public static final byte[] unpackCacheContainer(byte[] packedData) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(packedData);
|
||||
int compression = buffer.get() & 0xFF;
|
||||
int containerSize = buffer.getInt();
|
||||
if (containerSize < 0 || containerSize > 5000000) {
|
||||
return null;
|
||||
// throw new RuntimeException();
|
||||
}
|
||||
if (compression == 0) {
|
||||
byte unpacked[] = new byte[containerSize];
|
||||
buffer.get(unpacked, 0, containerSize);
|
||||
return unpacked;
|
||||
}
|
||||
int decompressedSize = buffer.getInt();
|
||||
if (decompressedSize < 0 || decompressedSize > 20000000) {
|
||||
return null;
|
||||
// throw new RuntimeException();
|
||||
}
|
||||
byte decompressedData[] = new byte[decompressedSize];
|
||||
if (compression == 1) {
|
||||
BZip2Decompressor.decompress(decompressedData, packedData, containerSize, 9);
|
||||
} else {
|
||||
GZipDecompressor.decompress(buffer, decompressedData);
|
||||
}
|
||||
return decompressedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container indexes.
|
||||
* @return The container indexes.
|
||||
*/
|
||||
public int[] getContainersIndexes() {
|
||||
return containersIndexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the containers.
|
||||
* @return The containers.
|
||||
*/
|
||||
public FilesContainer[] getContainers() {
|
||||
return containers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the information container.
|
||||
* @return The information container.
|
||||
*/
|
||||
public Container getInformationContainer() {
|
||||
return informationContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the revision.
|
||||
* @return The revision.
|
||||
*/
|
||||
public int getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the containers information.
|
||||
* @param data The data.
|
||||
*/
|
||||
public void decodeContainersInformation(byte[] data) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||
protocol = buffer.get() & 0xFF;
|
||||
if (protocol != 5 && protocol != 6) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
revision = protocol < 6 ? 0 : buffer.getInt();
|
||||
int nameHash = buffer.get() & 0xFF;
|
||||
filesNamed = (0x1 & nameHash) != 0;
|
||||
whirpool = (0x2 & nameHash) != 0;
|
||||
containersIndexes = new int[buffer.getShort() & 0xFFFF];
|
||||
int lastIndex = -1;
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
containersIndexes[index] = (buffer.getShort() & 0xFFFF) + (index == 0 ? 0 : containersIndexes[index - 1]);
|
||||
if (containersIndexes[index] > lastIndex) {
|
||||
lastIndex = containersIndexes[index];
|
||||
}
|
||||
}
|
||||
containers = new FilesContainer[lastIndex + 1];
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
containers[containersIndexes[index]] = new FilesContainer();
|
||||
}
|
||||
if (filesNamed) {
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
containers[containersIndexes[index]].setNameHash(buffer.getInt());
|
||||
}
|
||||
}
|
||||
byte[][] filesHashes = null;
|
||||
if (whirpool) {
|
||||
filesHashes = new byte[containers.length][];
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
filesHashes[containersIndexes[index]] = new byte[64];
|
||||
buffer.get(filesHashes[containersIndexes[index]], 0, 64);
|
||||
}
|
||||
}
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
containers[containersIndexes[index]].setCrc(buffer.getInt());
|
||||
}
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
containers[containersIndexes[index]].setVersion(buffer.getInt());
|
||||
}
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
containers[containersIndexes[index]].setFilesIndexes(new int[buffer.getShort() & 0xFFFF]);
|
||||
}
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
int lastFileIndex = -1;
|
||||
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
|
||||
containers[containersIndexes[index]].getFilesIndexes()[fileIndex] = (buffer.getShort() & 0xFFFF) + (fileIndex == 0 ? 0 : containers[containersIndexes[index]].getFilesIndexes()[fileIndex - 1]);
|
||||
if (containers[containersIndexes[index]].getFilesIndexes()[fileIndex] > lastFileIndex) {
|
||||
lastFileIndex = containers[containersIndexes[index]].getFilesIndexes()[fileIndex];
|
||||
}
|
||||
}
|
||||
containers[containersIndexes[index]].setFiles(new Container[lastFileIndex + 1]);
|
||||
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
|
||||
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]] = new Container();
|
||||
}
|
||||
}
|
||||
if (whirpool) {
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
|
||||
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]].setVersion(filesHashes[containersIndexes[index]][containers[containersIndexes[index]].getFilesIndexes()[fileIndex]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filesNamed) {
|
||||
for (int index = 0; index < containersIndexes.length; index++) {
|
||||
for (int fileIndex = 0; fileIndex < containers[containersIndexes[index]].getFilesIndexes().length; fileIndex++) {
|
||||
containers[containersIndexes[index]].getFiles()[containers[containersIndexes[index]].getFilesIndexes()[fileIndex]].setNameHash(buffer.getInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If is whirpool.
|
||||
* @return If is whirpool {@code true}.
|
||||
*/
|
||||
public boolean isWhirpool() {
|
||||
return whirpool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data.
|
||||
* @return The data.
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package core.cache.misc;
|
||||
|
||||
/**
|
||||
* A class holding the file containers.
|
||||
* @author Dragonkk
|
||||
*/
|
||||
public final class FilesContainer extends Container {
|
||||
|
||||
/**
|
||||
* The file indexes.
|
||||
*/
|
||||
private int[] filesIndexes;
|
||||
|
||||
/**
|
||||
* The files.
|
||||
*/
|
||||
private Container[] files;
|
||||
|
||||
/**
|
||||
* Construct a new files container.
|
||||
*/
|
||||
public FilesContainer() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the files.
|
||||
* @param containers The files.
|
||||
*/
|
||||
public void setFiles(Container[] containers) {
|
||||
this.files = containers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the files.
|
||||
* @return The files.
|
||||
*/
|
||||
public Container[] getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file indexes.
|
||||
* @param containersIndexes The file indexes.
|
||||
*/
|
||||
public void setFilesIndexes(int[] containersIndexes) {
|
||||
this.filesIndexes = containersIndexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file indexes.
|
||||
* @return The file indexes.
|
||||
*/
|
||||
public int[] getFilesIndexes() {
|
||||
return filesIndexes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package core.cache.misc.buffer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Handles the reading of data from a byte buffer.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class BufferInputStream extends InputStream {
|
||||
|
||||
/**
|
||||
* The buffer to write on.
|
||||
*/
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
/**
|
||||
* The buffer input stream.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public BufferInputStream(ByteBuffer buffer) throws IOException {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return buffer.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffer.
|
||||
* @return The buffer.
|
||||
*/
|
||||
public ByteBuffer getBuffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package core.cache.misc.buffer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Handles the writing of data on a byte buffer.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class BufferOutputStream extends OutputStream {
|
||||
|
||||
/**
|
||||
* The buffer to write on.
|
||||
*/
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code BufferOutputStream} {@code Object}.
|
||||
* @param buffer The buffer to write on.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
* @throws SecurityException If a security manager exists and its
|
||||
* checkPermission method denies enabling subclassing.
|
||||
*/
|
||||
public BufferOutputStream(ByteBuffer buffer) throws IOException, SecurityException {
|
||||
super();
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
buffer.put((byte) b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffer.
|
||||
* @return The buffer.
|
||||
*/
|
||||
public ByteBuffer getBuffer() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package core.cache.misc.buffer;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Holds utility methods for reading/writing a byte buffer.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class ByteBufferUtils {
|
||||
|
||||
/**
|
||||
* Gets a string from the byte buffer.
|
||||
* @param buffer The byte buffer.
|
||||
* @return The string.
|
||||
*/
|
||||
public static String getString(ByteBuffer buffer) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte b;
|
||||
while ((b = buffer.get()) != 0) {
|
||||
sb.append((char) b);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a string on the byte buffer.
|
||||
* @param s The string to put.
|
||||
* @param buffer The byte buffer.
|
||||
*/
|
||||
public static void putString(String s, ByteBuffer buffer) {
|
||||
buffer.put(s.getBytes(StandardCharsets.UTF_8)).put((byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string from the byte buffer.
|
||||
* @param s The string.
|
||||
* @param buffer The byte buffer.
|
||||
* @return The string.
|
||||
*/
|
||||
public static ByteBuffer putGJ2String(String s, ByteBuffer buffer) {
|
||||
byte[] packed = new byte[256];
|
||||
int length = packGJString2(0, packed, s);
|
||||
return buffer.put((byte) 0).put(packed, 0, length).put((byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the XTEA encryption.
|
||||
* @param keys The keys.
|
||||
* @param start The start index.
|
||||
* @param end The end index.
|
||||
* @param buffer The byte buffer.
|
||||
*/
|
||||
public static void decodeXTEA(int[] keys, int start, int end, ByteBuffer buffer) {
|
||||
int l = buffer.position();
|
||||
buffer.position(start);
|
||||
int length = (end - start) / 8;
|
||||
for (int i = 0; i < length; i++) {
|
||||
int firstInt = buffer.getInt();
|
||||
int secondInt = buffer.getInt();
|
||||
int sum = 0xc6ef3720;
|
||||
int delta = 0x9e3779b9;
|
||||
for (int j = 32; j-- > 0;) {
|
||||
secondInt -= keys[(sum & 0x1c84) >>> 11] + sum ^ (firstInt >>> 5 ^ firstInt << 4) + firstInt;
|
||||
sum -= delta;
|
||||
firstInt -= (secondInt >>> 5 ^ secondInt << 4) + secondInt ^ keys[sum & 3] + sum;
|
||||
}
|
||||
buffer.position(buffer.position() - 8);
|
||||
buffer.putInt(firstInt);
|
||||
buffer.putInt(secondInt);
|
||||
}
|
||||
buffer.position(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String to an Integer?
|
||||
* @param position The position.
|
||||
* @param buffer The buffer used.
|
||||
* @param string The String to convert.
|
||||
* @return The Integer.
|
||||
*/
|
||||
public static int packGJString2(int position, byte[] buffer, String string) {
|
||||
int length = string.length();
|
||||
int offset = position;
|
||||
for (int i = 0; length > i; i++) {
|
||||
int character = string.charAt(i);
|
||||
if (character > 127) {
|
||||
if (character > 2047) {
|
||||
buffer[offset++] = (byte) ((character | 919275) >> 12);
|
||||
buffer[offset++] = (byte) (128 | ((character >> 6) & 63));
|
||||
buffer[offset++] = (byte) (128 | (character & 63));
|
||||
} else {
|
||||
buffer[offset++] = (byte) ((character | 12309) >> 6);
|
||||
buffer[offset++] = (byte) (128 | (character & 63));
|
||||
}
|
||||
} else
|
||||
buffer[offset++] = (byte) character;
|
||||
}
|
||||
return offset - position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a tri-byte from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getMedium(ByteBuffer buffer) {
|
||||
return ((buffer.get() & 0xFF) << 16) + ((buffer.get() & 0xFF) << 8) + (buffer.get() & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a smart from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getSmart(ByteBuffer buffer) {
|
||||
int peek = buffer.get() & 0xFF;
|
||||
if (peek <= Byte.MAX_VALUE) {
|
||||
return peek;
|
||||
}
|
||||
return ((peek << 8) | (buffer.get() & 0xFF)) - 32768;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a smart from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getBigSmart(ByteBuffer buffer) {
|
||||
int value = 0;
|
||||
int current = getSmart(buffer);
|
||||
while (current == 32767) {
|
||||
current = getSmart(buffer);
|
||||
value += 32767;
|
||||
}
|
||||
value += current;
|
||||
return value;
|
||||
}
|
||||
|
||||
/* *//**
|
||||
* Writes an object on the buffer.
|
||||
* @param buffer The buffer to write on.
|
||||
* @param o The object.
|
||||
*/
|
||||
/*
|
||||
* public static void putObject(ByteBuffer buffer, Object o) { ByteBuffer b;
|
||||
* try (ObjectOutputStream out = new ObjectOutputStream(new
|
||||
* BufferOutputStream(b = ByteBuffer.allocate(99999)))) {
|
||||
* out.writeObject(o); b.flip(); } catch (Throwable e) {
|
||||
* e.printStackTrace(); b = (ByteBuffer) ByteBuffer.allocate(0).flip(); }
|
||||
* buffer.putInt(b.remaining()); if (b.remaining() > 0) { buffer.put(b); } }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets an object from the byte buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The object.
|
||||
*/
|
||||
public static Object getObject(ByteBuffer buffer) {
|
||||
int length = buffer.getInt();
|
||||
if (length > 0) {
|
||||
byte[] bytes = new byte[length];
|
||||
buffer.get(bytes);
|
||||
try (ObjectInputStream str = new ObjectInputStream(new BufferInputStream(ByteBuffer.wrap(bytes)))) {
|
||||
return (Object) str.readObject();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ByteBufferUtils} {@code Object}.
|
||||
*/
|
||||
private ByteBufferUtils() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package core.game.activity;
|
||||
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.tools.SystemLogger;
|
||||
import core.game.world.GameWorld;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Manages the activities.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class ActivityManager {
|
||||
|
||||
/**
|
||||
* The mapping of instanced activities.
|
||||
*/
|
||||
private static final Map<String, ActivityPlugin> ACTIVITIES = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ActivityManager} {@code Object}.
|
||||
*/
|
||||
private ActivityManager() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an activity plugin.
|
||||
* @param plugin The plugin to register.
|
||||
*/
|
||||
public static void register(ActivityPlugin plugin) {
|
||||
plugin.register();
|
||||
ACTIVITIES.put(plugin.getName(), plugin);
|
||||
if (!plugin.isInstanced()) {
|
||||
plugin.configure();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an instanced activity.
|
||||
* @param player The player.
|
||||
* @param name The name.
|
||||
* @param login If we are logging in.
|
||||
* @param args The arguments.
|
||||
*/
|
||||
public static boolean start(Player player, String name, boolean login, Object... args) {
|
||||
ActivityPlugin plugin = ACTIVITIES.get(name);
|
||||
if (plugin == null) {
|
||||
if (GameWorld.getSettings().isDevMode()) {
|
||||
SystemLogger.logErr(ActivityManager.class, "Unhandled activity - " + name + "!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (plugin.isInstanced()) {
|
||||
(plugin = plugin.newInstance(player)).configure();
|
||||
}
|
||||
return plugin.start(player, login, args);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
if (GameWorld.getSettings().isDevMode()) {
|
||||
player.getPacketDispatch().sendMessage("Error starting activity " + (plugin == null ? null : plugin.getName()) + "!");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the activity by the name.
|
||||
* @param name the name.
|
||||
* @return the activity.
|
||||
*/
|
||||
public static ActivityPlugin getActivity(String name) {
|
||||
return ACTIVITIES.get(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
package core.game.activity;
|
||||
|
||||
import core.ServerConstants;
|
||||
import core.game.node.entity.Entity;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.map.Region;
|
||||
import core.game.world.map.build.DynamicRegion;
|
||||
import core.game.world.map.zone.*;
|
||||
import core.game.world.map.zone.impl.MultiwayCombatZone;
|
||||
import core.plugin.Plugin;
|
||||
import core.plugin.PluginManifest;
|
||||
import core.plugin.PluginType;
|
||||
|
||||
/**
|
||||
* A plugin implementation used for activity plugins.
|
||||
* @author Emperor
|
||||
*/
|
||||
@PluginManifest(type = PluginType.ACTIVITY)
|
||||
public abstract class ActivityPlugin extends MapZone implements Plugin<Player> {
|
||||
|
||||
/**
|
||||
* If the activity is instanced.
|
||||
*/
|
||||
private boolean instanced;
|
||||
|
||||
/**
|
||||
* If the activity is multicombat.
|
||||
*/
|
||||
private boolean multicombat;
|
||||
|
||||
/**
|
||||
* If the activity is safe.
|
||||
*/
|
||||
private boolean safe;
|
||||
|
||||
/**
|
||||
* The region of the activity.
|
||||
*/
|
||||
protected DynamicRegion region;
|
||||
|
||||
/**
|
||||
* The base location.
|
||||
*/
|
||||
protected Location base;
|
||||
|
||||
/**
|
||||
* A location which the player is teleported to in the case of death, if this activity is safe.
|
||||
* Defaults to the home location of the server.
|
||||
*/
|
||||
protected Location safeRespawn = ServerConstants.HOME_LOCATION;
|
||||
|
||||
/**
|
||||
* The player.
|
||||
*/
|
||||
protected Player player;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ActivityPlugin} {@code Object}.
|
||||
* @param name The name.
|
||||
* @param instanced If the activity is instanced.
|
||||
* @param multicombat If the activity is multicombat.
|
||||
* @param safe If the activity is safe (the player does not lose his/her
|
||||
* items).
|
||||
*/
|
||||
public ActivityPlugin(String name, boolean instanced, boolean multicombat, boolean safe, ZoneRestriction... restrictions) {
|
||||
super(name, true, ZoneRestriction.RANDOM_EVENTS);
|
||||
for (ZoneRestriction restriction : restrictions) {
|
||||
addRestriction(restriction.getFlag());
|
||||
}
|
||||
this.instanced = instanced;
|
||||
this.multicombat = multicombat;
|
||||
this.safe = safe;
|
||||
if (safe) {
|
||||
setZoneType(ZoneType.SAFE.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(ZoneBorders borders) {
|
||||
if (multicombat) {
|
||||
MultiwayCombatZone.getInstance().register(borders);
|
||||
}
|
||||
super.register(borders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the region base location.
|
||||
*/
|
||||
protected void setRegionBase() {
|
||||
if (region != null) {
|
||||
if (multicombat) {
|
||||
region.toggleMulticombat();
|
||||
}
|
||||
setBase(Location.create(region.getBorders().getSouthWestX(), region.getBorders().getSouthWestY(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the region base for multiple regions.
|
||||
* @param regions The regions.
|
||||
*/
|
||||
protected void setRegionBase(DynamicRegion[] regions) {
|
||||
region = regions[0];
|
||||
Location l = region.getBaseLocation();
|
||||
for (DynamicRegion r : regions) {
|
||||
if (r.getX() > l.getX() || r.getY() > l.getY()) {
|
||||
l = r.getBaseLocation();
|
||||
}
|
||||
}
|
||||
ZoneBorders borders = new ZoneBorders(region.getX() << 6, region.getY() << 6, l.getX() + Region.SIZE, l.getY() + Region.SIZE);
|
||||
RegionZone multiZone = multicombat ? new RegionZone(MultiwayCombatZone.getInstance(), borders) : null;
|
||||
RegionZone zone = new RegionZone(this, borders);
|
||||
for (DynamicRegion r : regions) {
|
||||
if (multicombat) {
|
||||
r.setMulticombat(true);
|
||||
r.getRegionZones().add(multiZone);
|
||||
}
|
||||
r.getRegionZones().add(zone);
|
||||
}
|
||||
setBase(Location.create(borders.getSouthWestX(), borders.getSouthWestY(), 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the activity for the player.
|
||||
* @param player The player.
|
||||
* @param login If the player is logging in.
|
||||
* @param args The arguments.
|
||||
* @return {@code True} if successfully started the activity.
|
||||
*/
|
||||
public boolean start(Player player, boolean login, Object... args) {
|
||||
this.player = player;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enter(Entity e) {
|
||||
Location l;
|
||||
if (e instanceof Player && (l = getSpawnLocation()) != null) {
|
||||
e.getProperties().setSpawnLocation(l);
|
||||
}
|
||||
e.getProperties().setSafeZone(safe);
|
||||
e.getProperties().safeRespawn = this.safeRespawn;
|
||||
e.setAttribute("activity", this);
|
||||
return super.enter(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean leave(Entity e, boolean logout) {
|
||||
if (e instanceof Player) {
|
||||
e.getProperties().setSpawnLocation(ServerConstants.HOME_LOCATION);
|
||||
}
|
||||
Location l;
|
||||
if (instanced && logout && (l = getSpawnLocation()) != null) {
|
||||
e.setLocation(l);
|
||||
}
|
||||
e.getProperties().setSafeZone(false);
|
||||
e.getProperties().safeRespawn = ServerConstants.HOME_LOCATION;
|
||||
e.removeAttribute("activity");
|
||||
return super.leave(e, logout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to do anything on registration.
|
||||
*/
|
||||
public void register() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fireEvent(String identifier, Object... args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract ActivityPlugin newInstance(Player p) throws Throwable;
|
||||
|
||||
/**
|
||||
* Gets the spawn location for this activity.
|
||||
*/
|
||||
public abstract Location getSpawnLocation();
|
||||
|
||||
/**
|
||||
* Gets the instanced.
|
||||
* @return The instanced.
|
||||
*/
|
||||
public boolean isInstanced() {
|
||||
return instanced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the instanced.
|
||||
* @param instanced The instanced to set.
|
||||
*/
|
||||
public void setInstanced(boolean instanced) {
|
||||
this.instanced = instanced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the multicombat.
|
||||
* @return The multicombat.
|
||||
*/
|
||||
public boolean isMulticombat() {
|
||||
return multicombat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the multicombat.
|
||||
* @param multicombat The multicombat to set.
|
||||
*/
|
||||
public void setMulticombat(boolean multicombat) {
|
||||
this.multicombat = multicombat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the safe.
|
||||
* @return The safe.
|
||||
*/
|
||||
public boolean isSafe() {
|
||||
return safe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the safe.
|
||||
* @param safe The safe to set.
|
||||
*/
|
||||
public void setSafe(boolean safe) {
|
||||
this.safe = safe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player.
|
||||
* @return The player.
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base.
|
||||
* @return The base.
|
||||
*/
|
||||
public Location getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base.
|
||||
* @param base The base to set.
|
||||
*/
|
||||
public void setBase(Location base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
package core.game.activity
|
||||
|
||||
import core.api.*
|
||||
import core.game.event.EventHook
|
||||
import core.game.event.SelfDeathEvent
|
||||
import core.game.component.Component
|
||||
import core.game.interaction.MovementPulse
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.Region
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.build.DynamicRegion
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.net.packet.PacketRepository
|
||||
import core.net.packet.context.MinimapStateContext
|
||||
import core.net.packet.out.MinimapState
|
||||
import org.rs09.consts.Components
|
||||
import core.ServerConstants
|
||||
import core.api.Event
|
||||
import core.api.utils.PlayerCamera
|
||||
import core.tools.SystemLogger
|
||||
import core.game.world.GameWorld
|
||||
|
||||
/**
|
||||
* A utility class for making cutscenes.
|
||||
* @author Ceikry
|
||||
*/
|
||||
abstract class Cutscene(val player: Player) {
|
||||
lateinit var region: Region
|
||||
lateinit var base: Location
|
||||
var exitLocation: Location = player.location.transform(0,0,0)
|
||||
var ended = false
|
||||
|
||||
val camera = PlayerCamera(player)
|
||||
private val addedNPCs = HashMap<Int, ArrayList<NPC>>()
|
||||
|
||||
abstract fun setup()
|
||||
abstract fun runStage(stage: Int)
|
||||
|
||||
/**
|
||||
* Creates a new dynamic copy of the region identified by regionId, sets this cutscene's region as this new copy, and clears any cutscene-spawned NPCs from the previous region.
|
||||
* @param regionId the region ID to duplicate.
|
||||
*/
|
||||
fun loadRegion(regionId: Int)
|
||||
{
|
||||
clearNPCs()
|
||||
logCutscene("Creating new instance of region $regionId for ${player.username}.")
|
||||
region = DynamicRegion.create(regionId)
|
||||
logCutscene("Dynamic region instantiated for ${player.username}. Global coordinates: ${region.baseLocation}.")
|
||||
base = region.baseLocation
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade the player's view to black. This process can be safely assumed to take about 8 ticks to complete.
|
||||
*/
|
||||
fun fadeToBlack()
|
||||
{
|
||||
logCutscene("Fading ${player.username}'s screen to black.")
|
||||
player.interfaceManager.closeOverlay()
|
||||
player.interfaceManager.openOverlay(Component(Components.FADE_TO_BLACK_120))
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade the player's view from black back to normal. This process can be safely assumed to take about 6 ticks to complete.
|
||||
*/
|
||||
fun fadeFromBlack()
|
||||
{
|
||||
logCutscene("Fading ${player.username}'s screen from black to normal.")
|
||||
player.interfaceManager.closeOverlay()
|
||||
player.interfaceManager.openOverlay(Component(Components.FADE_FROM_BLACK_170))
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports an entity to a pair of coordinates within the currently active cutscene region
|
||||
* @param entity the entity to teleport
|
||||
* @param regionX the region X coordinate to teleport the entity to (0-63)
|
||||
* @param regionY the region Y coordinate to teleport the entity to (0-63)
|
||||
* @param plane (optional) the plane to teleport to (0-3)
|
||||
*/
|
||||
fun teleport(entity: Entity, regionX: Int, regionY: Int, plane: Int = 0)
|
||||
{
|
||||
val newLoc = base.transform(regionX, regionY, plane)
|
||||
logCutscene("Teleporting ${entity.username} to coordinates: LOCAL[$regionX,$regionY,$plane] GLOBAL[${newLoc.x},${newLoc.y},$plane].")
|
||||
entity.properties.teleportLocation = newLoc
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an entity to the given coordinates within the currently active cutscene region
|
||||
* @param entity the entity to move
|
||||
* @param regionX the region X coordinate to move the entity to (0-63)
|
||||
* @param regionY the region Y coordinate to move the entity to (0-63)
|
||||
*/
|
||||
fun move(entity: Entity, regionX: Int, regionY: Int)
|
||||
{
|
||||
logCutscene("Moving ${entity.username} to LOCAL[$regionX,$regionY].")
|
||||
entity.pulseManager.run(object : MovementPulse(entity, base.transform(regionX,regionY,0), Pathfinder.SMART) {
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a dialogue to the player using the given NPC ID, which updates the cutscene stage by default when continued.
|
||||
* @param npcId the ID of the NPC to send a dialogue for
|
||||
* @param expression the FacialExpression the NPC should use
|
||||
* @param message the message to send
|
||||
* @param onContinue (optional) a method that runs when the dialogue is "continued." Increments the cutscene stage by default.
|
||||
*/
|
||||
fun dialogueUpdate(npcId: Int, expression: core.game.dialogue.FacialExpression, message: String, onContinue: () -> Unit = {incrementStage()})
|
||||
{
|
||||
logCutscene("Sending NPC dialogue update.")
|
||||
sendNPCDialogue(player, npcId, message, expression)
|
||||
player.dialogueInterpreter.addAction { _,_ -> onContinue.invoke() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a non-NPC dialogue to the player, which updates the cutscene stage by default when continued
|
||||
* @param message the message to send
|
||||
* @param onContinue (optional) a method that runs when the dialogue is "continued." Increments the cutscene stage by default.
|
||||
*/
|
||||
fun dialogueUpdate(message: String, onContinue: () -> Unit = {incrementStage()})
|
||||
{
|
||||
logCutscene("Sending standard dialogue update.")
|
||||
sendDialogue(player, message)
|
||||
player.dialogueInterpreter.addAction {_,_ -> onContinue.invoke()}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a player dialogue, which updates the cutscene stage by default when continued
|
||||
* @param expression the FacialExpression to use
|
||||
* @param message the message to send
|
||||
* @param onContinue (optional) a method that runs when the dialogue is "continued." Increments the cutscene stage by default.
|
||||
*/
|
||||
fun playerDialogueUpdate(expression: core.game.dialogue.FacialExpression, message: String, onContinue: () -> Unit = {incrementStage()})
|
||||
{
|
||||
logCutscene("Sending player dialogue update")
|
||||
sendPlayerDialogue(player, message, expression)
|
||||
player.dialogueInterpreter.addAction{_,_ -> onContinue.invoke()}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the stage after a set number of ticks.
|
||||
* @param ticks the number of ticks to wait
|
||||
* @param newStage (optional) the new stage to update to. If not passed, stage is incremented instead.
|
||||
*/
|
||||
fun timedUpdate(ticks: Int, newStage: Int = -1)
|
||||
{
|
||||
logCutscene("Executing timed updated for $ticks ticks.")
|
||||
GameWorld.Pulser.submit(object : Pulse(ticks)
|
||||
{
|
||||
override fun pulse(): Boolean {
|
||||
if(newStage == -1)
|
||||
incrementStage()
|
||||
else
|
||||
updateStage(newStage)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the first NPC from the added-to-cutscene NPCs with a matching ID.
|
||||
* @param id the ID to grab for.
|
||||
* @return the first NPC, or null if there are no matching NPCs.
|
||||
*/
|
||||
fun getNPC(id: Int): NPC?
|
||||
{
|
||||
return addedNPCs[id]?.firstOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all NPCs from the added-to-cutscene NPCs with a matching ID.
|
||||
* @param id the ID to grab for.
|
||||
* @return an ArrayList of the matching NPCs, which will be empty if there were no matches.
|
||||
*/
|
||||
fun getNPCs(id: Int): ArrayList<NPC>
|
||||
{
|
||||
return addedNPCs[id] ?: ArrayList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the object in the region at the given regionX and regionY
|
||||
* @param regionX the region-local X coordinate to grab the object from (0-63)
|
||||
* @param regionY the region-local Y coordinate to grab the object from (0-63)
|
||||
* @param plane the plane to grab the object from (0-3)
|
||||
*/
|
||||
fun getObject(regionX: Int, regionY: Int, plane: Int = 0): Scenery?
|
||||
{
|
||||
val obj = RegionManager.getObject(base.transform(regionX,regionY,plane))
|
||||
logCutscene("Retrieving object at LOCAL[$regionX,$regionY], GOT: ${obj?.definition?.name ?: "null"}.")
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an NPC to the cutscene with the given ID, at the region-local X and Y coordinates.
|
||||
* @param id the ID of the NPC to add.
|
||||
* @param regionX the region-local X coordinate to place the NPC at
|
||||
* @param regionY the region-local Y coordinate to place the NPC at
|
||||
* @param direction the direction the NPC faces when it is initially placed.
|
||||
* @param plane the plane to place te NPC on. Default is 0.
|
||||
*/
|
||||
fun addNPC(id: Int, regionX: Int, regionY: Int, direction: Direction, plane: Int = 0)
|
||||
{
|
||||
val npc = NPC(id)
|
||||
npc.isRespawn = false
|
||||
npc.isAggressive = false
|
||||
npc.isWalks = false
|
||||
npc.location = base.transform(regionX, regionY, plane)
|
||||
npc.init()
|
||||
npc.faceLocation(npc.location.transform(direction))
|
||||
|
||||
val npcs = addedNPCs[id] ?: ArrayList()
|
||||
npcs.add(npc)
|
||||
addedNPCs[id] = npcs
|
||||
logCutscene("Added NPC $id at location LOCAL[$regionX,$regionY,$plane] GLOBAL[${npc.location.x},${npc.location.y},$plane]")
|
||||
}
|
||||
|
||||
fun start()
|
||||
{
|
||||
logCutscene("Starting cutscene for ${player.username}.")
|
||||
region = RegionManager.forId(player.location.regionId)
|
||||
base = RegionManager.forId(player.location.regionId).baseLocation
|
||||
setup()
|
||||
PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 2))
|
||||
runStage(player.getCutsceneStage())
|
||||
setAttribute(player, ATTRIBUTE_CUTSCENE, this)
|
||||
setAttribute(player, ATTRIBUTE_CUTSCENE_STAGE, 0)
|
||||
player.interfaceManager.removeTabs(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14)
|
||||
player.properties.isSafeZone = true
|
||||
player.properties.safeRespawn = player.location
|
||||
player.lock()
|
||||
player.hook(Event.SelfDeath, CUTSCENE_DEATH_HOOK)
|
||||
player.logoutListeners["cutscene"] = {player -> player.location = exitLocation; player.getCutscene()?.end() }
|
||||
content.global.ame.RandomEventManager.getInstance(player)!!.enabled = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends this cutscene, fading the screen to black, teleporting the player to the exit location, and then fading it back in and executing the endActions passed to this method.
|
||||
* @param endActions (optional) a method that executes when the cutscene fully completes
|
||||
*/
|
||||
fun end(endActions: (() -> Unit)? = null)
|
||||
{
|
||||
ended = true
|
||||
fadeToBlack()
|
||||
GameWorld.Pulser.submit(object : Pulse(){
|
||||
var tick: Int = 0
|
||||
override fun pulse(): Boolean {
|
||||
when(tick++)
|
||||
{
|
||||
8 -> player.properties.teleportLocation = exitLocation
|
||||
9 -> fadeFromBlack()
|
||||
16 -> {
|
||||
try {
|
||||
endActions?.invoke()
|
||||
} catch (e: Exception) {
|
||||
SystemLogger.logErr(this::class.java, "There's some bad nasty code in ${this::class.java.simpleName} end actions!")
|
||||
e.printStackTrace()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
player ?: return
|
||||
player.removeAttribute(ATTRIBUTE_CUTSCENE)
|
||||
player.removeAttribute(ATTRIBUTE_CUTSCENE_STAGE)
|
||||
player.properties.isSafeZone = false
|
||||
player.properties.safeRespawn = ServerConstants.HOME_LOCATION
|
||||
player.interfaceManager.restoreTabs()
|
||||
player.unlock()
|
||||
clearNPCs()
|
||||
player.unhook(CUTSCENE_DEATH_HOOK)
|
||||
player.logoutListeners.remove("cutscene")
|
||||
content.global.ame.RandomEventManager.getInstance(player)?.enabled = true
|
||||
PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 0))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the camera to the specified regionX and regionY
|
||||
* @param regionX the region-local X coordinate to move the camera to (0-63)
|
||||
* @param regionY the region-local Y coordinate to move the camera to (0-63)
|
||||
* @param height (optional) the height of the camera, defaults to 300.
|
||||
* @param speed (optional) the speed of the camera transition, defaults to 100.
|
||||
*/
|
||||
fun moveCamera(regionX: Int, regionY: Int, height: Int = 300, speed: Int = 100)
|
||||
{
|
||||
val globalLoc = base.transform(regionX, regionY, 0)
|
||||
camera.panTo(globalLoc.x, globalLoc.y, height, speed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the camera to face the given region-local X and Y coordinates
|
||||
* @param regionX the region-local X coordinate to rotate the camera to (0-63)
|
||||
* @param regionY the region-local Y coordinate to rotate the camera to (0-63)
|
||||
* @param height (optional) the height of the camera, defaults to 300.
|
||||
* @param speed (optional) the speed of the camera transition, defaults to 100.
|
||||
*/
|
||||
fun rotateCamera(regionX: Int, regionY: Int, height: Int = 300, speed: Int = 100)
|
||||
{
|
||||
val globalLoc = base.transform(regionX, regionY, 0)
|
||||
camera.rotateTo(globalLoc.x, globalLoc.y, height, speed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location the player is placed at when the cutscene ends.
|
||||
*/
|
||||
fun setExit(location: Location)
|
||||
{
|
||||
exitLocation = location
|
||||
}
|
||||
|
||||
private fun loadCurrentStage()
|
||||
{
|
||||
if(ended) return
|
||||
runStage(player.getCutsceneStage())
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the player's stage attribute by 1
|
||||
*/
|
||||
fun incrementStage()
|
||||
{
|
||||
setAttribute(player, ATTRIBUTE_CUTSCENE_STAGE, player.getCutsceneStage() + 1)
|
||||
loadCurrentStage()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player's stage attribute to a new stage
|
||||
*/
|
||||
fun updateStage(newStage: Int)
|
||||
{
|
||||
setAttribute(player, ATTRIBUTE_CUTSCENE_STAGE, newStage)
|
||||
loadCurrentStage()
|
||||
}
|
||||
|
||||
fun logCutscene(message: String)
|
||||
{
|
||||
if(ServerConstants.LOG_CUTSCENE)
|
||||
SystemLogger.logInfo(this::class.java, "$message")
|
||||
}
|
||||
|
||||
fun clearNPCs() {
|
||||
for(entry in addedNPCs.entries)
|
||||
{
|
||||
logCutscene("Clearing ${entry.value.size} NPCs with ID ${entry.key} for ${player.username}.")
|
||||
for(npc in entry.value) npc.clear()
|
||||
}
|
||||
addedNPCs.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ATTRIBUTE_CUTSCENE = "cutscene"
|
||||
const val ATTRIBUTE_CUTSCENE_STAGE = "cutscene:stage"
|
||||
object CUTSCENE_DEATH_HOOK : EventHook<SelfDeathEvent>
|
||||
{
|
||||
override fun process(entity: Entity, event: SelfDeathEvent) {
|
||||
if(entity !is Player) return
|
||||
entity.getCutscene()?.end() ?: entity.unhook(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
package core.game.activity;
|
||||
|
||||
import core.game.component.Component;
|
||||
import core.game.node.entity.Entity;
|
||||
import core.game.node.entity.npc.NPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.system.task.Pulse;
|
||||
import core.game.world.GameWorld;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.map.build.DynamicRegion;
|
||||
import core.net.packet.PacketRepository;
|
||||
import core.net.packet.context.MinimapStateContext;
|
||||
import core.net.packet.out.MinimapState;
|
||||
import core.plugin.PluginManifest;
|
||||
import core.plugin.PluginType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the plugin used to handle a cutscene.
|
||||
* @author Vexia
|
||||
* @date 28/12/2013
|
||||
*/
|
||||
@PluginManifest(type = PluginType.ACTIVITY)
|
||||
public abstract class CutscenePlugin extends ActivityPlugin {
|
||||
|
||||
/**
|
||||
* The list of tabs to remove.
|
||||
*/
|
||||
private static final int[] TABS = new int[] { 0, 1, 2, 3, 4, 5, 6, 11, 12 };
|
||||
|
||||
/**
|
||||
* The npcs in our cutscene.
|
||||
*/
|
||||
protected final List<NPC> npcs = new ArrayList<>(100);
|
||||
|
||||
/**
|
||||
* The start pulse used for effect.
|
||||
*/
|
||||
private final StartPulse startPulse = new StartPulse();
|
||||
|
||||
/**
|
||||
* The ending pulse used for effect.
|
||||
*/
|
||||
private final EndPulse endPulse = new EndPulse();
|
||||
|
||||
/**
|
||||
* If we should use a fade in or not.
|
||||
*/
|
||||
private final boolean fade;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code CutscenePlugin} {@code Object}.
|
||||
* @param name the name of the cutscene/mapzone.
|
||||
* @param fade fading in or not.
|
||||
*/
|
||||
public CutscenePlugin(String name, final boolean fade) {
|
||||
super(name, true, false, true);
|
||||
this.fade = fade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code CutscenePlugin} {@code Object}.
|
||||
* @param name the name.
|
||||
*/
|
||||
public CutscenePlugin(final String name) {
|
||||
this(name, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start(final Player player, boolean login, Object... args) {
|
||||
player.setAttribute("cutscene:original-loc", player.getLocation());
|
||||
player.removeAttribute("real-end");
|
||||
player.setAttribute("real-end", player.getLocation());
|
||||
if (isFade()) {
|
||||
GameWorld.getPulser().submit(getStartPulse());
|
||||
} else {
|
||||
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, getMapState()));
|
||||
player.getInterfaceManager().removeTabs(getRemovedTabs());
|
||||
player.getProperties().setTeleportLocation(getStartLocation());
|
||||
player.unlock();
|
||||
player.getWalkingQueue().reset();
|
||||
player.getLocks().lockMovement(1000000);
|
||||
player.getInterfaceManager().close();
|
||||
open();
|
||||
}
|
||||
player.lock();
|
||||
return super.start(player, login, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean leave(final Entity e, boolean logout) {
|
||||
if (player != null) {
|
||||
if (logout) {
|
||||
player.setLocation(player.getAttribute("cutscene:original-loc", player.getLocation()));
|
||||
end();
|
||||
} else {
|
||||
unpause();
|
||||
}
|
||||
player.unlock();
|
||||
player.getInterfaceManager().openDefaultTabs();
|
||||
player.getWalkingQueue().reset();
|
||||
player.getLocks().unlockMovement();
|
||||
}
|
||||
return super.leave(e, logout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fireEvent(String identifier, Object... args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to stop the cutscene.
|
||||
* @param fade if we should use a fade cutout.
|
||||
*/
|
||||
public void stop(boolean fade) {
|
||||
if (fade) {
|
||||
GameWorld.getPulser().submit(endPulse);
|
||||
} else {
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to end the cutscene.
|
||||
*/
|
||||
public void end() {
|
||||
if (region != null) {
|
||||
for (int i = 0; i < region.getPlanes().length; i++) {
|
||||
for (NPC n : region.getPlanes()[i].getNpcs()) {
|
||||
if (n == null) {
|
||||
continue;
|
||||
}
|
||||
n.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
|
||||
player.getInterfaceManager().restoreTabs();
|
||||
player.unlock();// incase he was locked.
|
||||
player.getWalkingQueue().reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the pulse used when starting a cutscene. This is used to give
|
||||
* dramatic effect for entering a cutscene. In the future allow for this to
|
||||
* be toggled.
|
||||
* @author 'Vexia
|
||||
* @date 30/12/2013
|
||||
*/
|
||||
public class StartPulse extends Pulse {
|
||||
|
||||
/**
|
||||
* Represents the counter.
|
||||
*/
|
||||
private int counter = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code StartPulse} {@code Object}.
|
||||
*/
|
||||
public StartPulse() {
|
||||
super(1, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
switch (counter++) {
|
||||
case 1:
|
||||
player.lock();
|
||||
player.getInterfaceManager().openOverlay(new Component(115));
|
||||
break;
|
||||
case 3:
|
||||
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, getMapState()));
|
||||
player.getInterfaceManager().removeTabs(getRemovedTabs());
|
||||
break;
|
||||
case 4:
|
||||
player.getProperties().setTeleportLocation(getStartLocation());
|
||||
break;
|
||||
case 5:
|
||||
player.getInterfaceManager().closeOverlay();
|
||||
player.getInterfaceManager().close();
|
||||
player.unlock();
|
||||
player.getWalkingQueue().reset();
|
||||
player.getLocks().lockMovement(1000000);
|
||||
open();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the pulse used when ending a cutscene. This is used to give
|
||||
* dramatic effect for entering a cutscene.
|
||||
* @author 'Vexia
|
||||
* @date 30/12/2013
|
||||
*/
|
||||
public class EndPulse extends Pulse {
|
||||
|
||||
/**
|
||||
* Represents the counter.
|
||||
*/
|
||||
private int counter = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code EndPulse} {@code Object}.
|
||||
*/
|
||||
public EndPulse() {
|
||||
super(1, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
switch (counter++) {
|
||||
case 1:
|
||||
player.lock();
|
||||
player.getInterfaceManager().openOverlay(new Component(115));
|
||||
break;
|
||||
case 3:
|
||||
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, getMapState()));
|
||||
player.getInterfaceManager().removeTabs(getRemovedTabs());
|
||||
break;
|
||||
case 4:
|
||||
Location loc = (Location) (player.getAttribute("real-end", player.getAttribute("cutscene:original-loc", player.getLocation())));
|
||||
player.getProperties().setTeleportLocation(loc);
|
||||
break;
|
||||
case 5:
|
||||
end();
|
||||
stop();
|
||||
fade();// specfic for fadeout.
|
||||
if (player.getSession().isActive()) {
|
||||
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
|
||||
}
|
||||
player.getInterfaceManager().closeOverlay();
|
||||
if (player.getSession().isActive()) {
|
||||
player.getInterfaceManager().close();
|
||||
}
|
||||
player.getProperties().setSafeZone(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called when the dim interface is closed. And you can see the
|
||||
* cutscene.
|
||||
*/
|
||||
public void open() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called on the end of the cutscene.
|
||||
*/
|
||||
public void fade() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mapstate to use. (override if needed).
|
||||
* @return the state.
|
||||
*/
|
||||
public int getMapState() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the removed tabs. (override if needed).
|
||||
* @return the tabs.
|
||||
*/
|
||||
public int[] getRemovedTabs() {
|
||||
return TABS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the starting location (region based, override if needed).
|
||||
* @return the location.
|
||||
*/
|
||||
public Location getStartLocation() {
|
||||
return getBase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to unpause this cutscene.
|
||||
*/
|
||||
public final void unpause() {
|
||||
stop(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player.
|
||||
* @return The player.
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the region.
|
||||
* @return The region.
|
||||
*/
|
||||
public DynamicRegion getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nPCS.
|
||||
* @return The nPCS.
|
||||
*/
|
||||
public List<NPC> getNPCS() {
|
||||
return npcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fade.
|
||||
* @return The fade.
|
||||
*/
|
||||
public boolean isFade() {
|
||||
return fade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start pulse.
|
||||
* @return the pulse.
|
||||
*/
|
||||
public Pulse getStartPulse() {
|
||||
return startPulse;
|
||||
}
|
||||
|
||||
public Pulse getEndPulse(){return new EndPulse();}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,578 @@
|
||||
package core.game.bots;
|
||||
|
||||
import core.game.node.entity.impl.PulseType;
|
||||
import core.ServerConstants;
|
||||
import core.game.container.impl.EquipmentContainer;
|
||||
import core.game.interaction.DestinationFlag;
|
||||
import core.game.interaction.MovementPulse;
|
||||
import core.game.node.Node;
|
||||
import core.game.node.entity.Entity;
|
||||
import core.game.node.entity.npc.NPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.info.PlayerDetails;
|
||||
import core.game.node.entity.player.link.appearance.Gender;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.world.map.Direction;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.map.RegionManager;
|
||||
import core.game.world.map.path.Pathfinder;
|
||||
import core.game.world.map.zone.impl.WildernessZone;
|
||||
import core.game.world.repository.Repository;
|
||||
import core.net.packet.context.MessageContext;
|
||||
import core.tools.RandomFunction;
|
||||
import core.tools.StringUtils;
|
||||
import core.game.node.entity.skill.Skills;
|
||||
import content.region.misc.tutisland.handlers.iface.CharacterDesign;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents an <b>A</b>rtificial <b>I</b>ntelligent <b>P</b>layer.
|
||||
*
|
||||
* @author Emperor
|
||||
*/
|
||||
public class AIPlayer extends Player {
|
||||
|
||||
/**
|
||||
* The current UID.
|
||||
*/
|
||||
private static int currentUID = 0x1;
|
||||
|
||||
private static final List<String> botNames = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* The active Artificial intelligent players mapping.
|
||||
*/
|
||||
private static final Map<Integer, AIPlayer> botMapping = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A line of data from namesandarmor.txt that will be used to generate the appearance
|
||||
* Data in format:
|
||||
* //name:cblevel:helmet:cape:neck:weapon:chest:shield:unknown:legs:unknown:gloves:boots:
|
||||
*/
|
||||
private static String OSRScopyLine;
|
||||
|
||||
/**
|
||||
* The AIP's UID.
|
||||
*/
|
||||
private final int uid;
|
||||
|
||||
/**
|
||||
* The start location of the AIP.
|
||||
*/
|
||||
private final Location startLocation;
|
||||
|
||||
/**
|
||||
* The username.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* The player controlling this AIP.
|
||||
*/
|
||||
private Player controler;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new {@code AIPlayer} {@code Object}.
|
||||
*
|
||||
* @param l The location.
|
||||
*/
|
||||
static {
|
||||
loadNames("botnames.txt");
|
||||
}
|
||||
|
||||
public AIPlayer(Location l) {
|
||||
this(getRandomName(), l, null);
|
||||
}
|
||||
|
||||
public AIPlayer(String fileName, Location l) {
|
||||
this(retrieveRandomName(fileName), l, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private AIPlayer(String name, Location l, String ignored) {
|
||||
super(new PlayerDetails("/aip" + (currentUID + 1) + ":" + name));
|
||||
super.setLocation(startLocation = l);
|
||||
super.artificial = true;
|
||||
super.getDetails().setSession(ArtificialSession.getSingleton());
|
||||
Repository.getPlayers().add(this);
|
||||
this.username = StringUtils.formatDisplayName(name + (currentUID + 1));
|
||||
this.uid = currentUID++;
|
||||
this.updateRandomValues();
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates bot stats/equipment/etc based on OSRScopyLine
|
||||
*/
|
||||
public void updateRandomValues() {
|
||||
this.getAppearance().setGender(RandomFunction.random(5) == 1 ? Gender.FEMALE : Gender.MALE);
|
||||
int setTo = RandomFunction.random(0,10);
|
||||
CharacterDesign.randomize(this,true);
|
||||
this.setDirection(Direction.values()[new Random().nextInt(Direction.values().length)]); //Random facing dir
|
||||
this.getSkills().updateCombatLevel();
|
||||
this.getAppearance().sync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
return;
|
||||
}
|
||||
|
||||
private void setLevels() {
|
||||
//Create realistic player stats
|
||||
int maxLevel = RandomFunction.random(1, Math.min(parseOSRS(1), 99));
|
||||
for (int i = 0; i < Skills.NUM_SKILLS; i++) {
|
||||
this.getSkills().setStaticLevel(i, RandomFunction.linearDecreaseRand(maxLevel));
|
||||
}
|
||||
int combatLevelsLeft = parseOSRS(1);
|
||||
int hitpoints = Math.max(RandomFunction.random(10, Math.min(maxLevel, combatLevelsLeft * 4)), 10);
|
||||
combatLevelsLeft -= 0.25 * hitpoints;
|
||||
int prayer = combatLevelsLeft > 0 ? RandomFunction.random(Math.min(maxLevel, combatLevelsLeft * 8)) : 1;
|
||||
combatLevelsLeft -= 0.125 * prayer;
|
||||
int defence = combatLevelsLeft > 0 ? RandomFunction.random(Math.min(maxLevel, combatLevelsLeft * 4)) : 1;
|
||||
combatLevelsLeft -= 0.25 * defence;
|
||||
|
||||
combatLevelsLeft = Math.min(combatLevelsLeft, 199);
|
||||
|
||||
int attack = combatLevelsLeft > 0 ? RandomFunction.normalRandDist(Math.min(maxLevel, combatLevelsLeft * 3)) : 1;
|
||||
int strength = combatLevelsLeft > 0 ? combatLevelsLeft * 3 - attack : 1;
|
||||
|
||||
this.getSkills().setStaticLevel(Skills.HITPOINTS, hitpoints);
|
||||
this.getSkills().setStaticLevel(Skills.PRAYER, prayer);
|
||||
this.getSkills().setStaticLevel(Skills.DEFENCE, defence);
|
||||
this.getSkills().setStaticLevel(Skills.ATTACK, attack);
|
||||
this.getSkills().setStaticLevel(Skills.STRENGTH, strength);
|
||||
this.getSkills().setStaticLevel(Skills.RANGE, combatLevelsLeft / 2);
|
||||
this.getSkills().setStaticLevel(Skills.MAGIC, combatLevelsLeft / 2);
|
||||
}
|
||||
|
||||
private void giveArmor() {
|
||||
//name:cblevel:helmet2:cape3:neck4:weapon5:chest6:shield7:unknown8:legs9:unknown10:gloves11:boots12:
|
||||
//sicriona:103:1163: 1023: 1725 :1333: 1127 :1201 :0: 1079 :0: 2922: 1061:0:
|
||||
equipIfExists(new Item(parseOSRS(2)), EquipmentContainer.SLOT_HAT);
|
||||
equipIfExists(new Item(parseOSRS(3)), EquipmentContainer.SLOT_CAPE);
|
||||
equipIfExists(new Item(parseOSRS(4)), EquipmentContainer.SLOT_AMULET);
|
||||
equipIfExists(new Item(parseOSRS(5)), EquipmentContainer.SLOT_WEAPON);
|
||||
equipIfExists(new Item(parseOSRS(6)), EquipmentContainer.SLOT_CHEST);
|
||||
equipIfExists(new Item(parseOSRS(7)), EquipmentContainer.SLOT_SHIELD);
|
||||
equipIfExists(new Item(parseOSRS(9)), EquipmentContainer.SLOT_LEGS);
|
||||
equipIfExists(new Item(parseOSRS(11)), EquipmentContainer.SLOT_HANDS);
|
||||
equipIfExists(new Item(parseOSRS(12)), EquipmentContainer.SLOT_FEET);
|
||||
}
|
||||
|
||||
private int parseOSRS(int index) {
|
||||
return Integer.parseInt(OSRScopyLine.split(":")[index]);
|
||||
}
|
||||
|
||||
private void equipIfExists(Item e, int slot) {
|
||||
if (e == null || e.getName().equalsIgnoreCase("null")) {
|
||||
return;
|
||||
}
|
||||
if (e.getId() != 0)
|
||||
getEquipment().replace(e, slot);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a list of bot names into memory
|
||||
*/
|
||||
public static void loadNames(String fileName){
|
||||
try {
|
||||
Scanner sc = new Scanner(new File(ServerConstants.BOT_DATA_PATH + fileName));
|
||||
while (sc.hasNextLine()) {
|
||||
botNames.add(sc.nextLine());
|
||||
}
|
||||
} catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRandomName(){
|
||||
int index = (RandomFunction.random(botNames.size()));
|
||||
String name = botNames.get(index);
|
||||
botNames.remove(index);
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bot content
|
||||
*/
|
||||
public static void updateRandomOSRScopyLine(String fileName) {
|
||||
Random rand = new Random();
|
||||
int n = 0;
|
||||
try {
|
||||
for (Scanner sc = new Scanner(new File(ServerConstants.BOT_DATA_PATH + fileName)); sc.hasNext(); ) {
|
||||
++n;
|
||||
String line = sc.nextLine();
|
||||
if (rand.nextInt(n) == 0) { //Chance of overwriting line is lower and lower
|
||||
if (line.length() < 3 || line.startsWith("#")) //probably an empty line
|
||||
{
|
||||
continue;
|
||||
}
|
||||
OSRScopyLine = line;
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("Missing " + fileName);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String retrieveRandomName(String fileName) {
|
||||
do {
|
||||
updateRandomOSRScopyLine(fileName);
|
||||
} while (OSRScopyLine.startsWith("#") || OSRScopyLine.contains("_") || OSRScopyLine.contains(" ")); //Comment
|
||||
return OSRScopyLine.split(":")[0];
|
||||
}
|
||||
|
||||
private static String retrieveRandomName() {
|
||||
return retrieveRandomName("namesandarmor.txt");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
getProperties().setSpawnLocation(startLocation);
|
||||
getInterfaceManager().openDefaultTabs();
|
||||
getSession().setObject(this);
|
||||
botMapping.put(uid, this);
|
||||
super.init();
|
||||
getSettings().setRunToggled(true);
|
||||
CharacterDesign.randomize(this, false);
|
||||
getPlayerFlags().setLastSceneGraph(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the following.
|
||||
*
|
||||
* @param e The entity to follow.
|
||||
*/
|
||||
public void follow(final Entity e) {
|
||||
getPulseManager().run(new MovementPulse(this, e, DestinationFlag.FOLLOW_ENTITY) {
|
||||
@Override
|
||||
public boolean pulse() {
|
||||
face(e);
|
||||
return false;
|
||||
}
|
||||
}, PulseType.STANDARD);
|
||||
}
|
||||
|
||||
public void randomWalkAroundPoint(Location point, int radius) {
|
||||
Pathfinder.find(this, point.transform(RandomFunction.random(radius, (radius * -1)), RandomFunction.random(radius, (radius * -1)), 0), true, Pathfinder.SMART).walk(this);
|
||||
}
|
||||
|
||||
public void randomWalk(int radiusX, int radiusY) {
|
||||
Pathfinder.find(this, this.getLocation().transform(RandomFunction.random(radiusX, (radiusX * -1)), RandomFunction.random(radiusY, (radiusY * -1)), 0), false, Pathfinder.SMART).walk(this);
|
||||
}
|
||||
|
||||
public void walkToPosSmart(int x, int y) {
|
||||
walkToPosSmart(new Location(x, y));
|
||||
}
|
||||
|
||||
public void walkToPosSmart(Location loc) {
|
||||
Pathfinder.find(this, loc, true, Pathfinder.SMART).walk(this);
|
||||
}
|
||||
|
||||
public void walkPos(int x, int y) {
|
||||
Pathfinder.find(this, new Location(x, y));
|
||||
}
|
||||
|
||||
public boolean checkVictimIsPlayer() {
|
||||
if (this.getProperties().getCombatPulse().getVictim() != null)
|
||||
if (this.getProperties().getCombatPulse().getVictim().isPlayer())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if(getSkullManager().isWilderness()) {
|
||||
getSkullManager().setLevel(WildernessZone.getWilderness(this));
|
||||
}
|
||||
if(getSkills().getLifepoints() <= 0){
|
||||
//deregister(this.uid);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Item getItemById(int id) {
|
||||
for (int i = 0; i < 28; i++) {
|
||||
Item item = this.getInventory().get(i);
|
||||
if (item != null) {
|
||||
if (item.getId() == id)
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void handleIncomingChat(MessageContext ctx){
|
||||
}
|
||||
|
||||
|
||||
private ArrayList<Node> getNodeInRange(int range, int entry) {
|
||||
int meX = this.getLocation().getX();
|
||||
int meY = this.getLocation().getY();
|
||||
ArrayList<Node> nodes = new ArrayList<Node>();
|
||||
for (NPC npc : RegionManager.getLocalNpcs(this, range)) {
|
||||
if (npc.getId() == entry)
|
||||
nodes.add(npc);
|
||||
}
|
||||
for (int x = 0; x < range; x++) {
|
||||
for (int y = 0; y < range - x; y++) {
|
||||
Node node = RegionManager.getObject(0, meX + x, meY + y);
|
||||
if (node != null)
|
||||
if (node.getId() == entry)
|
||||
nodes.add(node);
|
||||
Node node2 = RegionManager.getObject(0, meX + x, meY - y);
|
||||
if (node2 != null)
|
||||
if (node2.getId() == entry)
|
||||
nodes.add(node2);
|
||||
Node node3 = RegionManager.getObject(0, meX - x, meY + y);
|
||||
if (node3 != null)
|
||||
if (node3.getId() == entry)
|
||||
nodes.add(node3);
|
||||
Node node4 = RegionManager.getObject(0, meX - x, meY - y);
|
||||
if (node4 != null)
|
||||
if (node4.getId() == entry)
|
||||
nodes.add(node4);
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
private ArrayList<Node> getNodeInRange(int range, List<Integer> entrys) {
|
||||
int meX = this.getLocation().getX();
|
||||
int meY = this.getLocation().getY();
|
||||
//int meX2 = this.getLocation().getX();
|
||||
//System.out.println("local " + meX + " real x? " + meX2 );
|
||||
ArrayList<Node> nodes = new ArrayList<Node>();
|
||||
for (NPC npc : RegionManager.getLocalNpcs(this, range)) {
|
||||
if (entrys.contains(npc.getId()))
|
||||
nodes.add(npc);
|
||||
}
|
||||
for (int x = 0; x < range; x++) {
|
||||
for (int y = 0; y < range - x; y++) {
|
||||
Node node = RegionManager.getObject(0, meX + x, meY + y);
|
||||
if (node != null)
|
||||
if (entrys.contains(node.getId()))
|
||||
nodes.add(node);
|
||||
Node node2 = RegionManager.getObject(0, meX + x, meY - y);
|
||||
if (node2 != null)
|
||||
if (entrys.contains(node2.getId()))
|
||||
nodes.add(node2);
|
||||
Node node3 = RegionManager.getObject(0, meX - x, meY + y);
|
||||
if (node3 != null)
|
||||
if (entrys.contains(node3.getId()))
|
||||
nodes.add(node3);
|
||||
Node node4 = RegionManager.getObject(0, meX - x, meY - y);
|
||||
if (node4 != null)
|
||||
if (entrys.contains(node4.getId()))
|
||||
nodes.add(node4);
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public Node getClosestNodeWithEntryAndDirection(int range, int entry, Direction direction) {
|
||||
ArrayList<Node> nodeList = getNodeInRange(range, entry);
|
||||
if (nodeList.isEmpty()) {
|
||||
//System.out.println("nodelist empty");
|
||||
return null;
|
||||
}
|
||||
Node node = getClosestNodeinNodeListWithDirection(nodeList, direction);
|
||||
return node;
|
||||
}
|
||||
|
||||
public Node getClosestNodeWithEntry(int range, int entry) {
|
||||
ArrayList<Node> nodeList = getNodeInRange(range, entry);
|
||||
if (nodeList.isEmpty()) {
|
||||
//System.out.println("nodelist empty");
|
||||
return null;
|
||||
}
|
||||
Node node = getClosestNodeinNodeList(nodeList);
|
||||
return node;
|
||||
}
|
||||
|
||||
public Node getClosestNodeWithEntry(int range, List<Integer> entrys) {
|
||||
ArrayList<Node> nodeList = getNodeInRange(range, entrys);
|
||||
if (nodeList.isEmpty()) {
|
||||
//System.out.println("nodelist empty");
|
||||
return null;
|
||||
}
|
||||
Node node = getClosestNodeinNodeList(nodeList);
|
||||
return node;
|
||||
}
|
||||
|
||||
public Node getClosesCreature(int radius) {
|
||||
int distance = radius + 1;
|
||||
Node npcReturn = null;
|
||||
for (NPC npc : RegionManager.getLocalNpcs(this, radius)) {
|
||||
double distanceToNpc = npc.getLocation().getDistance(this.getLocation());
|
||||
if ((distanceToNpc) < distance) {
|
||||
distance = (int) distanceToNpc;
|
||||
npcReturn = npc;
|
||||
}
|
||||
}
|
||||
return npcReturn;
|
||||
}
|
||||
|
||||
public Node getClosesCreature(int radius, int entry) {
|
||||
int distance = radius + 1;
|
||||
Node npcReturn = null;
|
||||
for (NPC npc : RegionManager.getLocalNpcs(this, radius)) {
|
||||
double distanceToNpc = npc.getLocation().getDistance(this.getLocation());
|
||||
if (npc.getId() == entry) {
|
||||
if ((distanceToNpc) < distance) {
|
||||
distance = (int) distanceToNpc;
|
||||
npcReturn = npc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return npcReturn;
|
||||
}
|
||||
|
||||
public Node getClosesCreature(int radius, ArrayList<Integer> entrys) {
|
||||
int distance = radius + 1;
|
||||
Node npcReturn = null;
|
||||
for (NPC npc : RegionManager.getLocalNpcs(this, radius)) {
|
||||
double distanceToNpc = npc.getLocation().getDistance(this.getLocation());
|
||||
if (entrys.contains(npc.getId())) {
|
||||
if ((distanceToNpc) < distance) {
|
||||
distance = (int) distanceToNpc;
|
||||
npcReturn = npc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return npcReturn;
|
||||
}
|
||||
|
||||
private Node getClosestNodeinNodeListWithDirection(ArrayList<Node> nodes, Direction direction) {
|
||||
if (nodes.isEmpty()) {
|
||||
//System.out.println("nodelist empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
double distance = 0;
|
||||
Node nodeReturn = null;
|
||||
for (Node node : nodes) {
|
||||
double nodeDistance = this.getLocation().getDistance(node.getLocation());
|
||||
if ((nodeReturn == null || nodeDistance < distance) && node.getDirection() == direction) {
|
||||
distance = nodeDistance;
|
||||
nodeReturn = node;
|
||||
}
|
||||
}
|
||||
return nodeReturn;
|
||||
}
|
||||
|
||||
private Node getClosestNodeinNodeList(ArrayList<Node> nodes) {
|
||||
if (nodes.isEmpty()) {
|
||||
//System.out.println("nodelist empty");
|
||||
return null;
|
||||
}
|
||||
|
||||
double distance = 0;
|
||||
Node nodeReturn = null;
|
||||
for (Node node : nodes) {
|
||||
double nodeDistance = this.getLocation().getDistance(node.getLocation());
|
||||
if (nodeReturn == null || nodeDistance < distance) {
|
||||
distance = nodeDistance;
|
||||
nodeReturn = node;
|
||||
}
|
||||
}
|
||||
return nodeReturn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
botMapping.remove(uid);
|
||||
super.clear(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
if (getPlayerFlags().isUpdateSceneGraph()) {
|
||||
getPlayerFlags().setLastSceneGraph(getLocation());
|
||||
}
|
||||
super.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalizeDeath(Entity killer) {
|
||||
super.finalizeDeath(killer);
|
||||
fullRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the UID.
|
||||
*
|
||||
* @return the UID.
|
||||
*/
|
||||
public int getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregisters an AIP.
|
||||
*
|
||||
* @param uid The player's UID.
|
||||
*/
|
||||
public static void deregister(int uid) {
|
||||
AIPlayer player = botMapping.get(uid);
|
||||
if (player != null) {
|
||||
player.clear();
|
||||
Repository.getPlayers().remove(player);
|
||||
return;
|
||||
}
|
||||
//SystemLogger.logErr(this.getClass(), "Could not deregister AIP#" + uid + ": UID not added to the mapping!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the AIP for the given UID.
|
||||
*
|
||||
* @param uid The UID.
|
||||
* @return The AIPlayer.
|
||||
*/
|
||||
public static AIPlayer get(int uid) {
|
||||
return botMapping.get(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the startLocation.
|
||||
*/
|
||||
public Location getStartLocation() {
|
||||
return startLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controler.
|
||||
*
|
||||
* @return The controler.
|
||||
*/
|
||||
public Player getControler() {
|
||||
return controler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controler.
|
||||
*
|
||||
* @param controler The controler to set.
|
||||
*/
|
||||
public void setControler(Player controler) {
|
||||
this.controler = controler;
|
||||
}
|
||||
|
||||
|
||||
public void interact(Node n) {
|
||||
// InteractionPacket.handleObjectInteraction(this, 0, n.getLocation(), n.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package core.game.bots
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.item.GroundItem
|
||||
import core.game.ge.GrandExchangeOffer
|
||||
|
||||
/**
|
||||
* A repository for bots to make use of that can contain any info that might be useful to them.
|
||||
* @author Ceikry
|
||||
*/
|
||||
class AIRepository {
|
||||
companion object {
|
||||
val groundItems = HashMap<Player,ArrayList<GroundItem>>()
|
||||
val GEOffers = HashMap<Player, GrandExchangeOffer>()
|
||||
|
||||
@JvmStatic
|
||||
val PulseRepository = HashMap<String, GeneralBotCreator.BotScriptPulse>() // Lowercase username, pulse
|
||||
|
||||
@JvmStatic
|
||||
fun addItem(item: GroundItem){
|
||||
if(groundItems[item.dropper] == null){
|
||||
val list = ArrayList<GroundItem>()
|
||||
list.add(item)
|
||||
groundItems[item.dropper] = list
|
||||
return
|
||||
}
|
||||
groundItems[item.dropper]!!.add(item)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getItems(player: Player): ArrayList<GroundItem>?{
|
||||
return groundItems[player]
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addOffer(player: Player, offer: GrandExchangeOffer){
|
||||
GEOffers[player] = offer
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getOffer(player: Player): GrandExchangeOffer? {
|
||||
return GEOffers[player]
|
||||
}
|
||||
|
||||
@JvmStatic fun clearAllBots() {
|
||||
PulseRepository.forEach { (_, it) ->
|
||||
it.stop();
|
||||
it.botScript.bot.clear();
|
||||
AIPlayer.deregister((it.botScript.bot as AIPlayer).uid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package core.game.bots;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import core.net.IoSession;
|
||||
|
||||
/**
|
||||
* Represents an artificial networking session.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class ArtificialSession extends IoSession {
|
||||
|
||||
/**
|
||||
* The artificial session singleton.
|
||||
*/
|
||||
private static final ArtificialSession SINGLETON = new ArtificialSession();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ArtificialSession} {@code Object}.
|
||||
*/
|
||||
private ArtificialSession() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddress() {
|
||||
return "127.0.0.1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Object context, boolean instant) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queue(ByteBuffer buffer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the singleton.
|
||||
*/
|
||||
public static ArtificialSession getSingleton() {
|
||||
return SINGLETON;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package core.game.bots
|
||||
|
||||
import core.game.node.entity.player.link.appearance.Gender
|
||||
import core.game.node.entity.player.link.prayer.PrayerType
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.map.Direction
|
||||
import core.game.world.map.Location
|
||||
import core.tools.RandomFunction
|
||||
import core.game.consumable.Consumable
|
||||
import content.data.consumables.Consumables
|
||||
import core.game.consumable.Food
|
||||
import content.data.consumables.effects.HealingEffect
|
||||
import core.game.node.entity.skill.Skills
|
||||
import java.util.*
|
||||
|
||||
class CombatBot(location: Location) : AIPlayer(location) {
|
||||
var tick = 0
|
||||
|
||||
override fun updateRandomValues() {
|
||||
appearance.gender = if (RandomFunction.random(5) == 1) Gender.FEMALE else Gender.MALE
|
||||
setDirection(Direction.values()[Random().nextInt(Direction.values().size)]) //Random facing dir
|
||||
skills.updateCombatLevel()
|
||||
appearance.sync()
|
||||
}
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
this.tick++
|
||||
|
||||
//Despawn
|
||||
if (skills.lifepoints == 0) {
|
||||
//CombatBotAssembler.produce(CombatBotAssembler.Type.RANGE, CombatBotAssembler.Tier.LOW,this.location)
|
||||
deregister(uid)
|
||||
}
|
||||
}
|
||||
|
||||
fun CheckPrayer(type: Array<PrayerType?>) {
|
||||
for (i in type.indices) prayer.toggle(type[i])
|
||||
}
|
||||
|
||||
fun eat(foodId: Int) {
|
||||
val foodItem = Item(foodId)
|
||||
if (skills.getStaticLevel(Skills.HITPOINTS) >= skills.lifepoints * 3 && inventory.containsItem(foodItem)) {
|
||||
this.lock(3)
|
||||
//this.animate(new Animation(829));
|
||||
val food = inventory.getItem(foodItem)
|
||||
var consumable: Consumable? = Consumables.getConsumableById(food.id)
|
||||
if (consumable == null) {
|
||||
consumable = Food(IntArray(food.id), HealingEffect(1))
|
||||
}
|
||||
consumable.consume(food, this)
|
||||
properties.combatPulse.delayNextAttack(3)
|
||||
}
|
||||
if (!checkVictimIsPlayer()) if (!inventory.contains(foodId, 1)) inventory.add(Item(foodId, 5)) //Add Food to Inventory
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,532 @@
|
||||
package core.game.bots
|
||||
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.map.Location
|
||||
import core.tools.RandomFunction
|
||||
import org.rs09.consts.Items
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
/**
|
||||
* Assembles combat-style bots, intended to replace PVMBotBuilder.
|
||||
* @author Ceikry
|
||||
*/
|
||||
class CombatBotAssembler {
|
||||
enum class Type{
|
||||
RANGE,
|
||||
MAGE,
|
||||
MELEE
|
||||
}
|
||||
enum class Tier{
|
||||
LOW,
|
||||
MED,
|
||||
HIGH,
|
||||
PURE
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a bot with the specified parameters.
|
||||
* @param type the type of bot to produce. Melee, Ranged, or Mage.
|
||||
* @param tier specifies the range of skills the bot can have, and thereby, the gear. LOW, MED, or HIGH.
|
||||
* @param location the location that the bot spawns and respawns at.
|
||||
* @return an AIPlayer with the specified values.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun produce(type: Type, tier: Tier, location: Location): AIPlayer? {
|
||||
return when (type) {
|
||||
Type.RANGE -> assembleRangedBot(tier, location)
|
||||
Type.MELEE -> assembleMeleeBot(tier,location)
|
||||
Type.MAGE -> assembleMeleeBot(tier,location)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles a ranged bot with the specified values.
|
||||
* @param tier the tier to use which defines skill ranges and gear.
|
||||
* @param location the bot's spawn and respawn location
|
||||
* @param crossbow (optional) whether or not this bot should use a crossbow
|
||||
* @return a CombatBot with the specified values.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun assembleRangedBot(tier: Tier, location: Location, crossbow: Boolean? = null): CombatBot {
|
||||
val bot = CombatBot(location)
|
||||
|
||||
generateStats(bot, tier, Skills.RANGE, Skills.DEFENCE)
|
||||
gearRangedBot(bot, crossbow ?: Random().nextInt() % 2 == 0)
|
||||
return bot
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles a melee bot with the specified values.
|
||||
* @param tier the tier of the bot. Specifies levels and gear.
|
||||
* @param location the spawn and respawn location of the bot.
|
||||
* @return a CombatBot with the specified values.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun assembleMeleeBot(tier: Tier, location: Location): CombatBot {
|
||||
val bot = CombatBot(location)
|
||||
|
||||
generateStats(bot, tier, Skills.ATTACK, Skills.STRENGTH, Skills.DEFENCE)
|
||||
gearMeleeBot(bot)
|
||||
return bot
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles a melee bot with gear appropriate for killing dragons.
|
||||
* @param tier the tier of the bot, specifying levels and gear.
|
||||
* @param location the spawn and respawn location of the bot.
|
||||
* @return a CombatBot suited for killing dragons.
|
||||
* @author Kermit
|
||||
*/
|
||||
fun MeleeAdventurer(tier: Tier, location: Location): CombatBot {
|
||||
val bot = CombatBot(location)
|
||||
var max = 0
|
||||
val level = RandomFunction.random(25, 65).also {max = 99 }
|
||||
generateStats(bot,tier,Skills.ATTACK, Skills.STRENGTH, Skills.DEFENCE)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setStaticLevel(Skills.ATTACK, level + 5)
|
||||
bot.skills.setStaticLevel(Skills.STRENGTH, level + 5)
|
||||
bot.skills.setLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setLevel(Skills.ATTACK, level + 5)
|
||||
bot.skills.setLevel(Skills.STRENGTH, level + 5)
|
||||
bot.skills.updateCombatLevel()
|
||||
equipHighest(bot, MELEE_HELMS)
|
||||
equipHighest(bot, MELEE_TOP)
|
||||
equipHighest(bot, MELEE_LEG)
|
||||
equipHighest(bot, MELEE_WEP)
|
||||
equipHighest(bot, MELEE_SHIELD)
|
||||
equipHighest(bot, CAPE)
|
||||
equipHighest(bot, NNECK)
|
||||
equipHighest(bot, NGLOVES)
|
||||
equipHighest(bot, NBOOTS)
|
||||
bot.equipment.refresh()
|
||||
return bot
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles a melee bot with gear appropriate for killing dragons.
|
||||
* @param tier the tier of the bot, specifying levels and gear.
|
||||
* @param location the spawn and respawn location of the bot.
|
||||
* @return a CombatBot suited for killing dragons.
|
||||
* @author Kermit
|
||||
*/
|
||||
fun RangeAdventurer(tier: Tier, location: Location): CombatBot {
|
||||
val bot = CombatBot(location)
|
||||
var max = 0
|
||||
val level = RandomFunction.random(35, 65).also {max = 75 }
|
||||
generateStats(bot,tier,Skills.ATTACK, Skills.STRENGTH)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setStaticLevel(Skills.DEFENCE, level)
|
||||
bot.skills.setStaticLevel(Skills.RANGE, level + 10)
|
||||
bot.skills.setLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setLevel(Skills.DEFENCE, level)
|
||||
bot.skills.setLevel(Skills.RANGE, level + 10)
|
||||
bot.skills.updateCombatLevel()
|
||||
equipHighest(bot,RANGE_HELMS,65)
|
||||
equipHighest(bot,RANGE_TOPS,65)
|
||||
equipHighest(bot,RANGE_LEGS,65)
|
||||
equipHighest(bot,CROSSBOWS,50)
|
||||
equipHighest(bot, CAPE)
|
||||
equipHighest(bot, NRANGENECK)
|
||||
equipHighest(bot, NRANGESHIELD)
|
||||
equipHighest(bot, PCRANGE_BACK)
|
||||
equipHighest(bot, NGLOVES)
|
||||
equipHighest(bot, NRBOOTS)
|
||||
bot.equipment.add(Item(Items.BRONZE_BOLTS_877,100000),13,false,false)
|
||||
bot.equipment.refresh()
|
||||
return bot
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles a melee bot with gear appropriate for killing dragons.
|
||||
* @param tier the tier of the bot, specifying levels and gear.
|
||||
* @param location the spawn and respawn location of the bot.
|
||||
* @return a CombatBot suited for killing dragons.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun assembleMeleeDragonBot(tier: Tier, location: Location): CombatBot {
|
||||
val bot = CombatBot(location)
|
||||
generateStats(bot,tier,Skills.ATTACK, Skills.STRENGTH, Skills.DEFENCE)
|
||||
equipHighest(bot, MELEE_HELMS, 50)
|
||||
equipHighest(bot, MELEE_TOP, 40)
|
||||
equipHighest(bot, MELEE_LEG, 40)
|
||||
equipHighest(bot, MELEE_WEP, 60)
|
||||
equipHighest(bot, CAPE)
|
||||
equipHighest(bot, NGLOVES)
|
||||
equipHighest(bot, NBOOTS)
|
||||
bot.equipment.refresh()
|
||||
return bot
|
||||
}
|
||||
|
||||
/**
|
||||
* Assembles a ranged bot with gear appropriate for killing dragons.
|
||||
* @param tier the tier of the bot, specifying levels and gear.
|
||||
* @param location the spawn and respawn location of the bot.
|
||||
* @return a CombatBot suited for killing dragons.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun assembleRangeDragonBot(tier: Tier, location: Location): CombatBot {
|
||||
val bot = CombatBot(location)
|
||||
bot.fullRestore()
|
||||
generateStats(bot,tier,Skills.RANGE,Skills.DEFENCE)
|
||||
equipHighest(bot,RANGE_HELMS,50)
|
||||
equipHighest(bot,RANGE_TOPS,50)
|
||||
equipHighest(bot,RANGE_LEGS,50)
|
||||
equipHighest(bot,CROSSBOWS,50)
|
||||
equipHighest(bot, CAPE)
|
||||
equipHighest(bot, NGLOVES)
|
||||
equipHighest(bot, NRBOOTS)
|
||||
bot.equipment.add(Item(Items.BRONZE_BOLTS_877,100000),13,false,false)
|
||||
bot.equipment.refresh()
|
||||
return bot
|
||||
}
|
||||
|
||||
/**
|
||||
* Gears a ranged bot with the best gear for its stats.
|
||||
* @param bot the bot to gear
|
||||
* @param crossbow (optional) whether or not this bot should use a crossbow. Default is false.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun gearRangedBot(bot: AIPlayer, crossbow: Boolean? = false) {
|
||||
equipHighest(bot, RANGE_HELMS)
|
||||
equipHighest(bot, RANGE_TOPS)
|
||||
equipHighest(bot, RANGE_LEGS)
|
||||
equipHighest(bot, CAPE)
|
||||
equipHighest(bot, NGLOVES)
|
||||
equipHighest(bot, NRBOOTS)
|
||||
if(crossbow == true) { equipHighest(bot,CROSSBOWS); equipHighest(bot,MELEE_SHIELD); bot.equipment.add(Item(Items.BRONZE_BOLTS_877,Integer.MAX_VALUE),13,false,false) }
|
||||
else {equipHighest(bot, BOWS); bot.equipment.add(Item(Items.BRONZE_ARROW_882,Integer.MAX_VALUE),13,false,false) }
|
||||
bot.equipment.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gears a melee bot with the best gear for its stats.
|
||||
* @param bot the bot to gear.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun gearMeleeBot(bot: AIPlayer){
|
||||
equipHighest(bot, MELEE_HELMS)
|
||||
equipHighest(bot, MELEE_LEG)
|
||||
equipHighest(bot, MELEE_SHIELD)
|
||||
equipHighest(bot, MELEE_TOP)
|
||||
equipHighest(bot, CAPE)
|
||||
equipHighest(bot, NGLOVES)
|
||||
equipHighest(bot, NBOOTS)
|
||||
equipHighest(bot, MELEE_WEP)
|
||||
bot.equipment.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gears a Novice Pest control bot.
|
||||
* @author Sir Kermit & Ceikry
|
||||
*/
|
||||
fun gearPCnRangedBot(bot: AIPlayer, crossbow: Boolean? = false, vararg skills: Int) {
|
||||
var max = 0
|
||||
val level = RandomFunction.random(30, 70).also {max = 75 }
|
||||
bot.fullRestore()
|
||||
|
||||
bot.skills.setStaticLevel(Skills.RANGE, 50)
|
||||
bot.skills.setStaticLevel(Skills.DEFENCE, 50)
|
||||
bot.skills.setStaticLevel(Skills.ATTACK, level)
|
||||
bot.skills.setStaticLevel(Skills.STRENGTH, level)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setLevel(Skills.RANGE, 50)
|
||||
bot.skills.setLevel(Skills.DEFENCE, 50)
|
||||
bot.skills.setLevel(Skills.ATTACK, level)
|
||||
bot.skills.setLevel(Skills.STRENGTH, level)
|
||||
bot.skills.setLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.updateCombatLevel()
|
||||
equipHighest(bot, PCRANGE_HELMS)
|
||||
equipHighest(bot, PCRANGE_TOPS)
|
||||
equipHighest(bot, PCRANGE_BACK)
|
||||
equipHighest(bot, PCRANGE_LEGS)
|
||||
bot.equipment.refresh()
|
||||
equipHighest(bot, NECK)
|
||||
equipHighest(bot, GLOVES)
|
||||
equipHighest(bot, BOOTS)
|
||||
equipHighest(bot, RING_ARCH)
|
||||
bot.equipment.refresh()
|
||||
if(crossbow == true) { equipHighest(bot,PCCROSSBOWS); equipHighest(bot,MELEE_SHIELD); bot.equipment.add(Item(Items.BRONZE_BOLTS_877,Integer.MAX_VALUE),13,false,false) }
|
||||
else {equipHighest(bot, PCBOWS); bot.equipment.add(Item(Items.BRONZE_ARROW_882,Integer.MAX_VALUE),13,false,false) }
|
||||
bot.skills.setStaticLevel(Skills.RANGE, 99)
|
||||
bot.skills.setLevel(Skills.RANGE, 99)
|
||||
bot.equipment.refresh()
|
||||
}
|
||||
|
||||
fun gearPCnMeleeBot(bot: AIPlayer, vararg skills: Int){
|
||||
var max = 0
|
||||
val initial = RandomFunction.random(30, 75).also {max = 75 }
|
||||
var level = initial
|
||||
bot.fullRestore()
|
||||
|
||||
bot.skills.setStaticLevel(Skills.STRENGTH, level)
|
||||
bot.skills.setStaticLevel(Skills.DEFENCE, level)
|
||||
bot.skills.setStaticLevel(Skills.ATTACK, level)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setStaticLevel(Skills.PRAYER, 70)
|
||||
bot.skills.setStaticLevel(Skills.RANGE, 10)
|
||||
bot.skills.setStaticLevel(Skills.MAGIC, 10)
|
||||
bot.skills.setLevel(Skills.STRENGTH, level)
|
||||
bot.skills.setLevel(Skills.DEFENCE, level)
|
||||
bot.skills.setLevel(Skills.ATTACK, level)
|
||||
bot.skills.setLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setLevel(Skills.PRAYER, 70)
|
||||
bot.skills.setLevel(Skills.RANGE, 10)
|
||||
bot.skills.setLevel(Skills.MAGIC, 10)
|
||||
bot.skills.updateCombatLevel()
|
||||
equipHighest(bot, PCMELEE_HELMS)
|
||||
equipHighest(bot, PCMELEE_LEG)
|
||||
equipHighest(bot, PCMELEE_SHIELD)
|
||||
equipHighest(bot, PCMELEE_TOP)
|
||||
equipHighest(bot, PCMELEE_WEP)
|
||||
bot.equipment.refresh()
|
||||
equipHighest(bot, CAPE)
|
||||
equipHighest(bot, NECK)
|
||||
equipHighest(bot, GLOVES)
|
||||
equipHighest(bot, BOOTS)
|
||||
equipHighest(bot, RING_BERS)
|
||||
bot.equipment.refresh()
|
||||
bot.skills.setStaticLevel(Skills.DEFENCE, 70)
|
||||
bot.skills.setStaticLevel(Skills.ATTACK, 99)
|
||||
bot.skills.setStaticLevel(Skills.STRENGTH, 99)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS, 80)
|
||||
bot.skills.setLevel(Skills.DEFENCE, 70)
|
||||
bot.skills.setLevel(Skills.ATTACK, 99)
|
||||
bot.skills.setLevel(Skills.STRENGTH, 99)
|
||||
bot.skills.setLevel(Skills.HITPOINTS, 80)
|
||||
bot.fullRestore()
|
||||
}
|
||||
/**
|
||||
* Gears a Intermediate Pest control bot.
|
||||
* @author Sir Kermit & Ceikry
|
||||
*/
|
||||
fun gearPCiRangedBot(bot: AIPlayer, crossbow: Boolean? = false, vararg skills: Int) {
|
||||
var max = 0
|
||||
val level = RandomFunction.random(50, 80).also {max=99 }
|
||||
bot.fullRestore()
|
||||
|
||||
bot.skills.setStaticLevel(Skills.RANGE, level)
|
||||
bot.skills.setStaticLevel(Skills.DEFENCE, 80)
|
||||
bot.skills.setStaticLevel(Skills.ATTACK, level)
|
||||
bot.skills.setStaticLevel(Skills.STRENGTH, level)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS, 70)
|
||||
bot.skills.setStaticLevel(Skills.SUMMONING, 99)
|
||||
bot.skills.setLevel(Skills.RANGE, level)
|
||||
bot.skills.setLevel(Skills.DEFENCE, 80)
|
||||
bot.skills.setLevel(Skills.ATTACK, level)
|
||||
bot.skills.setLevel(Skills.STRENGTH, level)
|
||||
bot.skills.setLevel(Skills.HITPOINTS, 70)
|
||||
bot.skills.setLevel(Skills.SUMMONING, 99)
|
||||
bot.skills.updateCombatLevel()
|
||||
equipHighest(bot, PCRANGE_HELMS)
|
||||
equipHighest(bot, PCRANGE_TOPS)
|
||||
equipHighest(bot, PCRANGE_BACK)
|
||||
equipHighest(bot, PCRANGE_LEGS)
|
||||
bot.equipment.refresh()
|
||||
equipHighest(bot, GLOVES)
|
||||
equipHighest(bot, NECK)
|
||||
equipHighest(bot, BOOTS)
|
||||
equipHighest(bot, RING_ARCH)
|
||||
bot.equipment.refresh()
|
||||
if(crossbow == true) { equipHighest(bot,PCCROSSBOWS); equipHighest(bot,MELEE_SHIELD); bot.equipment.add(Item(Items.BRONZE_BOLTS_877,Integer.MAX_VALUE),13,false,false) }
|
||||
else {equipHighest(bot, PCBOWS); bot.equipment.add(Item(Items.BRONZE_ARROW_882,Integer.MAX_VALUE),13,false,false) }
|
||||
bot.skills.setStaticLevel(Skills.RANGE, 99)
|
||||
bot.skills.setLevel(Skills.RANGE, 99)
|
||||
bot.equipment.refresh()
|
||||
}
|
||||
|
||||
fun gearPCiMeleeBot(bot: AIPlayer, vararg skills: Int){
|
||||
var max = 0
|
||||
val initial = RandomFunction.random(55, 95).also {max=95 }
|
||||
var level = initial
|
||||
bot.fullRestore()
|
||||
|
||||
bot.skills.setStaticLevel(Skills.STRENGTH, level)
|
||||
bot.skills.setStaticLevel(Skills.DEFENCE, level)
|
||||
bot.skills.setStaticLevel(Skills.ATTACK, level)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setStaticLevel(Skills.PRAYER, 99)
|
||||
bot.skills.setStaticLevel(Skills.RANGE, level)
|
||||
bot.skills.setStaticLevel(Skills.MAGIC, level)
|
||||
bot.skills.setStaticLevel(Skills.SUMMONING, 99)
|
||||
bot.skills.setLevel(Skills.STRENGTH, level)
|
||||
bot.skills.setLevel(Skills.DEFENCE, level)
|
||||
bot.skills.setLevel(Skills.ATTACK, level)
|
||||
bot.skills.setLevel(Skills.HITPOINTS, level)
|
||||
bot.skills.setLevel(Skills.PRAYER, 99)
|
||||
bot.skills.setLevel(Skills.RANGE, level)
|
||||
bot.skills.setLevel(Skills.MAGIC, level)
|
||||
bot.skills.setLevel(Skills.SUMMONING, 99)
|
||||
bot.skills.updateCombatLevel()
|
||||
equipHighest(bot, PCMELEE_HELMS)
|
||||
equipHighest(bot, PCMELEE_LEG)
|
||||
equipHighest(bot, PCMELEE_SHIELD)
|
||||
equipHighest(bot, PCMELEE_TOP)
|
||||
equipHighest(bot, PCMELEE_WEP)
|
||||
bot.equipment.refresh()
|
||||
equipHighest(bot, CAPE)
|
||||
equipHighest(bot, NECK)
|
||||
equipHighest(bot, GLOVES)
|
||||
equipHighest(bot, BOOTS)
|
||||
equipHighest(bot, RING_BERS)
|
||||
bot.equipment.refresh()
|
||||
bot.skills.setStaticLevel(Skills.DEFENCE, 99)
|
||||
bot.skills.setStaticLevel(Skills.ATTACK, 99)
|
||||
bot.skills.setStaticLevel(Skills.STRENGTH, 99)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS, 99)
|
||||
bot.skills.setLevel(Skills.DEFENCE, 99)
|
||||
bot.skills.setLevel(Skills.ATTACK, 99)
|
||||
bot.skills.setLevel(Skills.STRENGTH, 99)
|
||||
bot.skills.setLevel(Skills.HITPOINTS, 99)
|
||||
bot.fullRestore()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates the stats for a bot with the given tier.
|
||||
* @param bot the bot to gear
|
||||
* @param tier the Tier of stats and gear. LOW, MED, HIGH, PURE.
|
||||
* @param skills the skills that we should generate.
|
||||
* @author Ceikry and Eli
|
||||
*/
|
||||
fun generateStats(bot: AIPlayer, tier: Tier, vararg skills: Int) {
|
||||
var totalXPAdd = 0.0
|
||||
var skillAmt = 0.0
|
||||
val variance = 0.5
|
||||
var max = 0
|
||||
val initial = when (tier) {
|
||||
Tier.LOW -> RandomFunction.random(33).also { max = 33 }
|
||||
Tier.MED -> RandomFunction.random(33, 66).also { max = 66 }
|
||||
Tier.HIGH -> RandomFunction.random(66, 99).also { max = 99 }
|
||||
Tier.PURE -> RandomFunction.random(90, 99).also {max = 99 }
|
||||
}
|
||||
for (skill in skills.indices) {
|
||||
val perc = RandomFunction.random(-variance,variance)
|
||||
var level = initial + (perc * 33).toInt()
|
||||
if(level < 1)
|
||||
level = 1
|
||||
if(level > max)
|
||||
level = max
|
||||
bot.skills.setLevel(skills[skill], level)
|
||||
bot.skills.setStaticLevel(skills[skill], level)
|
||||
totalXPAdd += bot.skills.getExperience(skills[skill])
|
||||
skillAmt++
|
||||
}
|
||||
when (tier){
|
||||
Tier.PURE -> {
|
||||
bot.skills.setStaticLevel(Skills.DEFENCE,10)
|
||||
bot.skills.setStaticLevel(Skills.STRENGTH,99)
|
||||
bot.skills.setStaticLevel(Skills.ATTACK,90)
|
||||
bot.skills.setStaticLevel(Skills.PRAYER,43)
|
||||
bot.skills.setStaticLevel(Skills.RANGE,1)
|
||||
bot.skills.setStaticLevel(Skills.MAGIC,1)
|
||||
}
|
||||
}
|
||||
|
||||
bot.skills.addExperience(Skills.HITPOINTS, (totalXPAdd / skillAmt) * 0.2)
|
||||
val new_hp = bot.skills.levelFromXP((totalXPAdd / skillAmt) * 0.2)
|
||||
bot.skills.setStaticLevel(Skills.HITPOINTS,10 + new_hp)
|
||||
bot.skills.updateCombatLevel()
|
||||
bot.fullRestore()
|
||||
}
|
||||
|
||||
/**
|
||||
* Equips the highest piece of gear from a set for the stats the bot has.
|
||||
* @param bot the bot to equip gear to.
|
||||
* @param set the IntArray set to check
|
||||
* @param levelcap (optional) the max level of gear to equip.
|
||||
* @author Ceikry
|
||||
*/
|
||||
private fun equipHighest(bot: AIPlayer, set: Array<Int>, levelcap: Int? = null) {
|
||||
val highestItems = ArrayList<Item>()
|
||||
var highest: Item? = null
|
||||
for (i in set.indices) {
|
||||
val item = Item(set[i])
|
||||
var canEquip = true
|
||||
(item.definition.handlers.getOrDefault("requirements",null) as HashMap<Int,Int>?)?.let { map ->
|
||||
levelcap?.let {levelcap ->
|
||||
map.map {
|
||||
if (bot.skills.getLevel(it.key) < it.value || it.value > levelcap)
|
||||
canEquip = false
|
||||
}
|
||||
} ?: map.map {
|
||||
if (bot.skills.getLevel(it.key) < it.value)
|
||||
canEquip = false
|
||||
}
|
||||
}
|
||||
if (canEquip) {
|
||||
if (highest == null) {
|
||||
highest = item
|
||||
highestItems.add(item)
|
||||
continue
|
||||
}
|
||||
if (item.lvlAvg() > highest.lvlAvg()) {
|
||||
highest = item
|
||||
highestItems.clear()
|
||||
highestItems.add(item)
|
||||
} else if(item.lvlAvg() == highest.lvlAvg()){
|
||||
highestItems.add(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
bot.equipment.add(highestItems.random(), highest!!.definition!!.handlers["equipment_slot"] as Int, false, false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension function for the Item class that gets the average of its level requirements.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun Item.lvlAvg(): Int {
|
||||
var total = 1
|
||||
var count = 1
|
||||
(definition.handlers.getOrDefault("requirements",null) as HashMap<Int,Int>?)?.let { map ->
|
||||
map.map {
|
||||
total += it.value
|
||||
count++
|
||||
}
|
||||
}
|
||||
return total / count
|
||||
}
|
||||
|
||||
|
||||
val RANGE_HELMS = arrayOf(1167,4732,3749)
|
||||
val RANGE_TOPS = arrayOf(1129,1131,1135,2499,2501,2503)
|
||||
val RANGE_LEGS = arrayOf(1095,1097,1099,2493,2495,2497)
|
||||
val BOWS = arrayOf(841,843,847,853)
|
||||
val CROSSBOWS = arrayOf(9185,9174,9177,9176,9179,9181,9183)
|
||||
|
||||
val PCRANGE_HELMS = arrayOf(1167,4732,3749,11718)
|
||||
val PCRANGE_TOPS = arrayOf(1129,1131,1135,2503,11720)
|
||||
val PCRANGE_LEGS = arrayOf(1095,1097,1099,2497,11722)
|
||||
val PCRANGE_BACK = arrayOf(1019,10498,10499)
|
||||
val PCBOWS = arrayOf(841,843,847,853)
|
||||
val PCCROSSBOWS = arrayOf(9185,9174,9177,9176,9179,9181,9183)
|
||||
|
||||
val MELEE_HELMS = arrayOf(1137,1139, 1141, 6621, 1143,1145,1147,1149,1151,1153, 6623, 1159,1163,1165,3748, 3751, 3753, 4716,4724, 4745, 4753)
|
||||
val MELEE_TOP = arrayOf(1101,1103,1105,1107,1109,1111,1113,2513,1115,1117,1119,1121,1123,1125,1127,4720,4728,4749,4749)
|
||||
val MELEE_LEG = arrayOf(1081,1083,1085,1087,1089,1091,1093,4759,1067,1069,1071,1073,1075,1077,1079,4722,4751,4722,4751)
|
||||
val MELEE_SHIELD = arrayOf(1171,1173,1175,1177,1179,1181,1183,1185,1187,1189,1191,1193,1195,1197,1199,1201)
|
||||
val MELEE_WEP = arrayOf(1277,1279,1281,1283,1285,1287,1289,1291,1293,1295,1297,1299,1301,1303,1305,1321,1323,1325,1327,1329,1331,1333,4587,4151,1363,1365,1367,1369,1371,1373,1375,1377)
|
||||
val NGLOVES = arrayOf(1059,2922,2912,2902,2932,2942,3799)
|
||||
val NBOOTS = arrayOf(4121,4123,4125,4127,4129,4131,1061,1837,2579,9005)
|
||||
val NRBOOTS = arrayOf(9006,626,628,630,632,634)
|
||||
val NNECK = arrayOf(1704,1725,1729,1731)
|
||||
val NRANGENECK = arrayOf(1478,1704)
|
||||
val NRANGESHIELD = arrayOf(1191,1193,1195,1197,1199,1201)
|
||||
|
||||
val PCMELEE_HELMS = arrayOf(1137,1139, 1141, 6621, 1143,1145,1147,1149,1151,1153, 6623, 1159,1163,1165,3748, 3751, 10828, 11335, 3753, 4716,4724, 4745, 4753, 3751)
|
||||
val PCMELEE_TOP = arrayOf(1101,1103,1105,1107,1109,1111,1113,2513,1115,1117,1119,1121,1123,1125,1127,4720,4728,4749,4749,11724,14479,2513)
|
||||
val PCMELEE_LEG = arrayOf(1081,1083,1085,1087,1089,1091,1093,4759,1067,1069,1071,1073,1075,1077,1079,4722,4751,4722,4751,11726,4087)
|
||||
val PCMELEE_SHIELD = arrayOf(1171,1173,1175,1177,1179,1181,1183,1185,1187,1189,1191,1193,1195,1197,1199,1201,6524,13742,13740,13738,13736,13734)
|
||||
val PCMELEE_WEP = arrayOf(1277,1279,1281,1283,1285,1287,1289,1291,1293,1295,1297,1299,1301,1303,1305,1321,1323,1325,1327,1329,1331,1333,4587,4151,1363,1365,1367,1369,1371,1373,1375,1377,1434,5698)
|
||||
|
||||
val NECK = arrayOf(1704,6585)
|
||||
val CAPE = arrayOf(1019,1021,1023,6568,4315,4317,4319,4321,4323,4325,4327,4329,4331,4333,4335,4337,4339,4341,4343,4345,4347,4349,4351)
|
||||
val GLOVES = arrayOf(1059,7456,7457,7458,7459,7460,7461,7462)
|
||||
val BOOTS = arrayOf(1061,4131,11732,11728,4131)
|
||||
val RING_BERS = arrayOf(6737)
|
||||
val RING_ARCH = arrayOf(6733)
|
||||
|
||||
val RICH_MELEE_HELMS = arrayOf(2587,2595,2605,2613,2619,2627,2657,2665,2673,3486,1149,10828,4716,4724,4753)
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package core.game.bots
|
||||
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.map.Location
|
||||
import core.tools.RandomFunction
|
||||
import core.Server
|
||||
import content.global.bots.Idler
|
||||
|
||||
class GeneralBotCreator {
|
||||
//org/crandor/net/packet/in/InteractionPacket.java <<< This is a very useful class for learning to code bots
|
||||
constructor(botScript: Script, loc: Location?) {
|
||||
botScript.bot = AIPBuilder.create(loc)
|
||||
GameWorld.Pulser.submit(BotScriptPulse(botScript))
|
||||
}
|
||||
|
||||
constructor(botScript: Script, bot: AIPlayer?) {
|
||||
botScript.bot = bot
|
||||
GameWorld.Pulser.submit(BotScriptPulse(botScript).also { AIRepository.PulseRepository[it.botScript.bot.username.lowercase()] = it })
|
||||
}
|
||||
|
||||
constructor(botScript: Script, player: Player, isPlayer: Boolean){
|
||||
botScript.bot = player
|
||||
val pulse = BotScriptPulse(botScript,isPlayer)
|
||||
GameWorld.Pulser.submit(pulse)
|
||||
player.setAttribute("/save:not_on_highscores",true)
|
||||
player.setAttribute("botting:script",pulse)
|
||||
}
|
||||
|
||||
inner class BotScriptPulse(public val botScript: Script, val isPlayer: Boolean = false) : Pulse(1){
|
||||
var ticks = 0
|
||||
init {
|
||||
botScript.init(isPlayer)
|
||||
}
|
||||
var randomDelay = 0
|
||||
|
||||
override fun pulse(): Boolean {
|
||||
if(randomDelay > 0){
|
||||
randomDelay -= 1
|
||||
return false
|
||||
}
|
||||
if (!botScript.bot.pulseManager.hasPulseRunning()) {
|
||||
|
||||
/*if (ticks++ >= RandomFunction.random(90000,120000)) {
|
||||
AIPlayer.deregister(botScript.bot.uid)
|
||||
ticks = 0
|
||||
SystemLogger.log("Submitting transition pulse from ticks")
|
||||
GameWorld.Pulser.submit(TransitionPulse(botScript))
|
||||
return true
|
||||
}*/
|
||||
if(!botScript.running) return true //has to be separated this way or it double-submits the respawn pulse.
|
||||
|
||||
|
||||
val idleRoll = RandomFunction.random(50)
|
||||
if(idleRoll == 2 && botScript !is Idler){
|
||||
randomDelay += RandomFunction.random(2,20)
|
||||
return false
|
||||
}
|
||||
botScript.tick()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
ticks = Integer.MAX_VALUE - 20 //Sets the ticks as high as they can go (safely) and then runs pulse again
|
||||
pulse() //to trigger the transition pulse to be submitted.
|
||||
super.stop()
|
||||
if (Server.running) AIRepository.PulseRepository.remove(this.botScript.bot.username.lowercase())
|
||||
}
|
||||
}
|
||||
|
||||
inner class TransitionPulse(val script: Script) : Pulse(RandomFunction.random(60,200)){
|
||||
override fun pulse(): Boolean {
|
||||
// This does not get called and should be removed
|
||||
GameWorld.Pulser.submit(BotScriptPulse(script.newInstance()).also { AIRepository.PulseRepository[it.botScript.bot.username.lowercase()] = it })
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package core.game.bots
|
||||
|
||||
annotation class PlayerCompatible
|
||||
@@ -0,0 +1,6 @@
|
||||
package core.game.bots
|
||||
|
||||
object PlayerScripts {
|
||||
class PlayerScript(val identifier: String, val description: Array<String>, val name: String, val clazz: Class<*>)
|
||||
val identifierMap = HashMap<String, PlayerScript>()
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package core.game.bots;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import core.game.consumable.Consumable;
|
||||
import content.data.consumables.Consumables;
|
||||
import core.game.consumable.Food;
|
||||
import content.data.consumables.effects.HealingEffect;
|
||||
import core.game.node.entity.skill.Skills;
|
||||
import core.game.node.entity.Entity;
|
||||
import core.game.node.entity.npc.NPC;
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.link.prayer.PrayerType;
|
||||
import core.game.node.item.Item;
|
||||
import core.game.world.map.Location;
|
||||
import core.game.world.map.RegionManager;
|
||||
import core.tools.RandomFunction;
|
||||
|
||||
public class PvMBots extends AIPlayer {
|
||||
|
||||
//Used so the bot doesn't spam actions
|
||||
private int tick = 0;
|
||||
|
||||
public PvMBots(Location l) {
|
||||
super(l);
|
||||
}
|
||||
|
||||
public PvMBots(String copyFromFile, Location l) {
|
||||
super(copyFromFile, l);
|
||||
}
|
||||
|
||||
|
||||
public List<Entity> FindTargets(Entity entity, int radius) {
|
||||
List<Entity> targets = new ArrayList<>(20);
|
||||
Object[] localNPCs = RegionManager.getLocalNpcs(entity,radius).toArray();
|
||||
int length = localNPCs.length;
|
||||
if(length > 5){length = 5;}
|
||||
for (int i = 0; i < length; i++) {
|
||||
NPC npc = (NPC) localNPCs[i];
|
||||
{
|
||||
if (checkValidTargets(npc))
|
||||
targets.add(npc);
|
||||
}
|
||||
}
|
||||
if (targets.size() == 0)
|
||||
return null;
|
||||
return targets;
|
||||
}
|
||||
|
||||
public boolean checkValidTargets(NPC target) {
|
||||
if (!target.isActive()) {
|
||||
return false;
|
||||
}
|
||||
if (!target.getProperties().isMultiZone() && target.inCombat()) {
|
||||
return false;
|
||||
}
|
||||
if (!target.getDefinition().hasAction("attack")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean AttackNpcsInRadius(int radius)
|
||||
{
|
||||
return AttackNpcsInRadius(this, radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attacks NPCs in radius of bot
|
||||
* @param bot
|
||||
* @param radius
|
||||
* @return true if bot will be fighting
|
||||
*/
|
||||
public boolean AttackNpcsInRadius(Player bot, int radius) {
|
||||
if (bot.inCombat())
|
||||
return true;
|
||||
List<Entity> creatures = FindTargets(bot, radius);
|
||||
if (creatures == null) {
|
||||
return false;
|
||||
}
|
||||
bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1))));
|
||||
if (!creatures.isEmpty()) {
|
||||
return true;
|
||||
} else {
|
||||
creatures = FindTargets(bot, radius);
|
||||
if (!creatures.isEmpty())
|
||||
{
|
||||
bot.attack(creatures.get(RandomFunction.getRandom((creatures.size() - 1))));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
this.tick++;
|
||||
|
||||
//Despawn
|
||||
if (this.getSkills().getLifepoints() <= 5){
|
||||
//TODO: Just respawn a new bot (not sure how you'd do that :L)
|
||||
// Maybe make all PvMBots know what to do if they aren't in right area? I.e. pest control bots teleport to PC
|
||||
//this.teleport(new Location(500, 500));
|
||||
//Despawning not being delayed causes 3 errors in the console
|
||||
this.getSkills().setLifepoints(20);
|
||||
}
|
||||
|
||||
//Npc Combat
|
||||
/*if (this.tick % 10 == 0) {
|
||||
if (!this.inCombat())
|
||||
AttackNpcsInRadius(this, 5);
|
||||
}*/
|
||||
|
||||
if (this.tick == 100) this.tick = 0;
|
||||
|
||||
//this.eat();
|
||||
//this.getPrayer().toggle()
|
||||
}
|
||||
|
||||
public void CheckPrayer(PrayerType type[]) {
|
||||
for (int i = 0; i < type.length; i++)
|
||||
this.getPrayer().toggle(type[i]);
|
||||
}
|
||||
|
||||
public void eat(int foodId) {
|
||||
Item foodItem = new Item(foodId);
|
||||
|
||||
if ((this.getSkills().getStaticLevel(Skills.HITPOINTS) >= this.getSkills().getLifepoints() * 3) && this.getInventory().containsItem(foodItem)) {
|
||||
this.lock(3);
|
||||
//this.animate(new Animation(829));
|
||||
Item food = this.getInventory().getItem(foodItem);
|
||||
|
||||
Consumable consumable = Consumables.getConsumableById(food.getId());
|
||||
|
||||
if (consumable == null) {
|
||||
consumable = new Food(new int[] {food.getId()}, new HealingEffect(1));
|
||||
}
|
||||
|
||||
consumable.consume(food, this);
|
||||
this.getProperties().getCombatPulse().delayNextAttack(3);
|
||||
}
|
||||
if (this.checkVictimIsPlayer() == false)
|
||||
if (!(this.getInventory().contains(foodId, 1)))
|
||||
this.getInventory().add(new Item(foodId, 5)); //Add Food to Inventory
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package core.game.bots
|
||||
|
||||
import core.game.world.map.Location
|
||||
import content.minigame.pestcontrol.bots.PestControlTestBot
|
||||
import content.minigame.pestcontrol.bots.PestControlTestBot2
|
||||
|
||||
// import sun.util.resources.CalendarData;
|
||||
class PvMBotsBuilder {
|
||||
|
||||
companion object {
|
||||
var botsSpawned = 0
|
||||
|
||||
fun create(l: Location?): PvMBots {
|
||||
botsSpawned++
|
||||
return PvMBots(l)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createPestControlTestBot2(l: Location?): PestControlTestBot2 {
|
||||
botsSpawned++
|
||||
return PestControlTestBot2(l!!)
|
||||
}
|
||||
@JvmStatic
|
||||
fun createPestControlTestBot(l: Location?): PestControlTestBot {
|
||||
botsSpawned++
|
||||
return PestControlTestBot(l!!)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package core.game.bots;
|
||||
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.item.Item;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class Script {
|
||||
|
||||
public ScriptAPI scriptAPI;
|
||||
public ArrayList<Item> inventory = new ArrayList<>(20);
|
||||
public ArrayList<Item> equipment = new ArrayList<>(20);
|
||||
public Map<Integer, Integer> skills = new HashMap<>();
|
||||
|
||||
|
||||
public Player bot;
|
||||
|
||||
public boolean running = true;
|
||||
|
||||
public void init(boolean isPlayer)
|
||||
{
|
||||
//bot.init();
|
||||
scriptAPI = new ScriptAPI(bot);
|
||||
|
||||
if(!isPlayer) {
|
||||
for (Item i : equipment) {
|
||||
bot.getEquipment().add(i, true, false);
|
||||
}
|
||||
bot.getInventory().clear();
|
||||
for (Item i : inventory) {
|
||||
bot.getInventory().add(i);
|
||||
}
|
||||
for (Map.Entry<Integer, Integer> skill : skills.entrySet()) {
|
||||
setLevel(skill.getKey(), skill.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return bot.getName() + " is a " + this.getClass().getSimpleName() + " at location " + bot.getLocation().toString() + " Current pulse: " + bot.getPulseManager().getCurrent();
|
||||
}
|
||||
|
||||
public abstract void tick();
|
||||
|
||||
public void setLevel(int skill, int level) {
|
||||
bot.getSkills().setLevel(skill, level);
|
||||
bot.getSkills().setStaticLevel(skill, level);
|
||||
bot.getSkills().updateCombatLevel();
|
||||
bot.getAppearance().sync();
|
||||
}
|
||||
|
||||
// This does not get called and all implementations should be removed
|
||||
public abstract Script newInstance();
|
||||
}
|
||||
@@ -0,0 +1,827 @@
|
||||
package core.game.bots
|
||||
|
||||
import core.api.*
|
||||
import core.cache.def.impl.ItemDefinition
|
||||
import core.game.component.Component
|
||||
import core.game.consumable.Consumable
|
||||
import content.data.consumables.Consumables
|
||||
import core.game.consumable.Food
|
||||
import content.data.consumables.effects.HealingEffect
|
||||
import core.game.interaction.DestinationFlag
|
||||
import core.game.interaction.MovementPulse
|
||||
import core.game.interaction.Option
|
||||
import core.game.node.Node
|
||||
import core.game.node.scenery.Scenery
|
||||
import core.game.node.entity.Entity
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
import core.game.node.entity.skill.Skills
|
||||
import core.game.node.item.GroundItem
|
||||
import core.game.node.item.GroundItemManager
|
||||
import core.game.node.item.Item
|
||||
import core.game.system.task.Pulse
|
||||
import core.game.world.map.Location
|
||||
import core.game.world.map.RegionManager
|
||||
import core.game.world.map.path.Pathfinder
|
||||
import core.game.world.update.flag.context.Animation
|
||||
import core.game.world.update.flag.context.ChatMessage
|
||||
import core.game.world.update.flag.context.Graphics
|
||||
import core.game.world.update.flag.player.ChatFlag
|
||||
import core.tools.RandomFunction
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.json.simple.JSONArray
|
||||
import org.json.simple.JSONObject
|
||||
import org.rs09.consts.Items
|
||||
import core.ServerConstants.Companion.SERVER_GE_NAME
|
||||
import core.game.ge.GrandExchange
|
||||
import core.game.ge.GrandExchangeOffer
|
||||
import core.game.interaction.IntType
|
||||
import core.game.interaction.InteractionListeners
|
||||
import core.tools.SystemLogger
|
||||
import core.game.system.config.ItemConfigParser
|
||||
import core.game.world.GameWorld
|
||||
import core.game.world.repository.Repository
|
||||
import core.tools.colorize
|
||||
import java.util.*
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class ScriptAPI(private val bot: Player) {
|
||||
val GRAPHICSUP = Graphics(1576)
|
||||
val ANIMATIONUP = Animation(8939)
|
||||
val GRAPHICSDOWN = Graphics(1577)
|
||||
val ANIMATIONDOWN = Animation(8941)
|
||||
|
||||
/**
|
||||
* Gets the distance between two nodes
|
||||
* @param n1 the first node
|
||||
* @param n2 the second node
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun distance(n1: Node, n2: Node): Double {
|
||||
return sqrt((n1.location.x - n2.location.x.toDouble()).pow(2.0) + (n2.location.y - n1.location.y.toDouble()).pow(2.0))
|
||||
}
|
||||
|
||||
fun interact(bot: Player, node: Node?, option: String){
|
||||
|
||||
if(node == null) return
|
||||
|
||||
val type = when(node){
|
||||
is Scenery -> IntType.SCENERY
|
||||
is NPC -> IntType.NPC
|
||||
is Item -> IntType.ITEM
|
||||
else -> null
|
||||
} ?: return
|
||||
val opt: Option? = node.interaction.options.filter {it != null && it.name.equals(option, true) }.firstOrNull()
|
||||
|
||||
if(opt == null){
|
||||
SystemLogger.logWarn(this::class.java, "Invalid option name provided: $option")
|
||||
return
|
||||
}
|
||||
|
||||
if(!InteractionListeners.run(node.id, type, option, bot, node)) node.interaction.handle(bot, opt)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nearest node with name entityName
|
||||
* @param entityName the name of the node to look for
|
||||
* @return the nearest node with a matching name or null
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun getNearestNode(entityName: String): Node? {
|
||||
var entity: Node? = null
|
||||
var minDistance = Double.MAX_VALUE
|
||||
for (node in RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities) {
|
||||
if (node != null && node.name == entityName && distance(bot, node) < minDistance && !Pathfinder.find(bot, node).isMoveNear) {
|
||||
entity = node
|
||||
minDistance = distance(bot, node)
|
||||
}
|
||||
}
|
||||
return entity
|
||||
}
|
||||
|
||||
fun sendChat(message: String) {
|
||||
bot.sendChat(message)
|
||||
bot.updateMasks.register(ChatFlag(ChatMessage(bot, message, 0, 0)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nearest node with a name contained in the list of acceptable names
|
||||
* @param acceptedNames the list of accepted npc/object names
|
||||
* @return the nearest node with a matching name or null
|
||||
* @author Ceikry
|
||||
*/
|
||||
|
||||
fun getNearestNodeFromList(acceptedNames: List<String>, isObject: Boolean): Node? {
|
||||
if (isObject) {
|
||||
var entity: Node? = null
|
||||
var minDistance = Double.MAX_VALUE
|
||||
for (objects in RegionManager.forId(bot.location.regionId).planes[bot.location.z].objects) {
|
||||
for(e in objects) {
|
||||
val name = e?.name
|
||||
if (e != null && acceptedNames.contains(name) && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear && e.isActive) {
|
||||
entity = e
|
||||
minDistance = distance(bot, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return if(entity == null) null else entity as Scenery
|
||||
} else {
|
||||
var entity: Node? = null
|
||||
var minDistance = Double.MAX_VALUE
|
||||
for (e in RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities) {
|
||||
val name = e?.name
|
||||
if (e != null && acceptedNames.contains(name) && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear) {
|
||||
entity = e
|
||||
minDistance = distance(bot, e)
|
||||
}
|
||||
}
|
||||
return entity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nearest node with matching id.
|
||||
* @param id the id to look for
|
||||
* @param object whether or not the node we are looking for is an object.
|
||||
* @return the closest node with matching id or null.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun getNearestNode(id: Int, `object`: Boolean): Node? {
|
||||
if (`object`) {
|
||||
var entity: Node? = null
|
||||
var minDistance = Double.MAX_VALUE
|
||||
for (objects in RegionManager.forId(bot.location.regionId).planes[bot.location.z].objects) {
|
||||
for(e in objects) {
|
||||
if (e != null && e.id == id && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear && e.isActive) {
|
||||
entity = e
|
||||
minDistance = distance(bot, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return if(entity == null) null else entity as Scenery
|
||||
} else {
|
||||
var entity: Node? = null
|
||||
var minDistance = Double.MAX_VALUE
|
||||
for (e in RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities) {
|
||||
if (e != null && e.id == id && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear) {
|
||||
entity = e
|
||||
minDistance = distance(bot, e)
|
||||
}
|
||||
}
|
||||
return entity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nearest node with a matching name.
|
||||
* @param name the name to look for.
|
||||
* @param object whether or not the node we are looking for is an object.
|
||||
* @return the nearest matching node or null.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun getNearestNode(name: String, `object`: Boolean): Node? {
|
||||
if (`object`) {
|
||||
var entity: Node? = null
|
||||
var minDistance = Double.MAX_VALUE
|
||||
for (objects in RegionManager.forId(bot.location.regionId).planes[bot.location.z].objects) {
|
||||
for(e in objects) {
|
||||
if (e != null && e.name.toLowerCase() == name.toLowerCase() && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear && e.isActive) {
|
||||
entity = e
|
||||
minDistance = distance(bot, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return if(entity == null) null else entity as Scenery
|
||||
} else {
|
||||
var entity: Node? = null
|
||||
var minDistance = Double.MAX_VALUE
|
||||
for (e in RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities) {
|
||||
if (e != null && e.name.toLowerCase() == name.toLowerCase() && distance(bot, e) < minDistance && !Pathfinder.find(bot, e).isMoveNear) {
|
||||
entity = e
|
||||
minDistance = distance(bot, e)
|
||||
}
|
||||
}
|
||||
return entity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nearest ground item with matching ID from the list in AIRepository.
|
||||
* @param id the id of the ground item we are looking for.
|
||||
* @return the nearest GroundItem with a matching id or null
|
||||
* @author Ceikry
|
||||
*/
|
||||
private fun getNearestGroundItem(id: Int): GroundItem? {
|
||||
var distance = 11.0
|
||||
var closest: GroundItem? = null
|
||||
if(AIRepository.getItems(bot) != null) {
|
||||
for (item in AIRepository.getItems(bot)!!.filter { it: GroundItem -> it.distance(bot.location) < 10 }) {
|
||||
if (item.id == id) {
|
||||
//distance = item.distance(bot.location)
|
||||
closest = item
|
||||
}
|
||||
}
|
||||
if (!GroundItemManager.getItems().contains(closest)){
|
||||
AIRepository.getItems(bot)?.remove(closest)
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
val items: ArrayList<GroundItem>? = bot.getAttribute("botting:drops",null)
|
||||
if(items != null){
|
||||
for(item in items.filter { it.distance(bot.location) < 10 }){
|
||||
if(item.id == id) return item.also { items.remove(item); bot.setAttribute("botting:drops",items) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return closest
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the nearest ground item with a matching id if it exists.
|
||||
* @param id the id to look for
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun takeNearestGroundItem(id: Int) : Boolean{
|
||||
val item = getNearestGroundItem(id)
|
||||
if(item != null){
|
||||
item.interaction?.handle(bot, item.interaction[2])
|
||||
return true
|
||||
}
|
||||
else return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nearest GameObject to loc with matching objectId
|
||||
* @param loc the location we are checking around
|
||||
* @param objectId the id of the object we are looking for
|
||||
* @return the nearest matching object or null.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun getNearestGameObject(loc: Location, objectId: Int): Scenery? {
|
||||
var nearestObject: Scenery? = null
|
||||
val minDistance = Double.MAX_VALUE
|
||||
for (o in RegionManager.forId(loc.regionId).planes[0].objects) {
|
||||
for (obj in o) {
|
||||
if (obj != null) {
|
||||
if (distance(loc, obj) < minDistance && obj.id == objectId) {
|
||||
nearestObject = obj
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nearestObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of NPCs that are attackable around the entity.
|
||||
* @param entity the entity to search around.
|
||||
* @param radius the radius around entity to search in.
|
||||
* @param name the name of the NPC to look for.
|
||||
* @return an Array of the nearest NPCs with matching name, or null.
|
||||
* @author Ceikry
|
||||
*/
|
||||
private fun findTargets(entity: Entity, radius: Int, name: String? = null): List<Entity>? {
|
||||
val targets: MutableList<Entity> = ArrayList()
|
||||
val localNPCs: Array<Any> = RegionManager.getLocalNpcs(entity, radius).toTypedArray()
|
||||
var length = localNPCs.size
|
||||
if (length > 5) {
|
||||
length = 5
|
||||
}
|
||||
for (i in 0 until length) {
|
||||
val npc = localNPCs[i] as NPC
|
||||
run { if (checkValidTargets(npc, name)) targets.add(npc) }
|
||||
}
|
||||
return if (targets.size == 0) null else targets
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given target is a valid target for a combat bot.
|
||||
* @param target the NPC that we are checking
|
||||
* @param name the expected name of the NPC.
|
||||
* @return true if the target is valid, false if not.
|
||||
* @author Ceikry
|
||||
*/
|
||||
private fun checkValidTargets(target: NPC, name: String?): Boolean {
|
||||
if (!target.isActive) {
|
||||
return false
|
||||
}
|
||||
if (!target.properties.isMultiZone && target.inCombat()) {
|
||||
return false
|
||||
}
|
||||
if (name != null){
|
||||
if(target.name != name)
|
||||
return false
|
||||
}
|
||||
return target.definition.hasAction("attack")
|
||||
}
|
||||
|
||||
/**
|
||||
* Attacks npcs in the given radius of the bot.
|
||||
* @param bot the bot that is attacking
|
||||
* @param radius the radius to attack in
|
||||
* @return true if successfully attacking an NPC within that radius, false if not.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun attackNpcsInRadius(bot: Player, radius: Int): Boolean {
|
||||
if (bot.inCombat()) return true
|
||||
var creatures: List<Entity>? = findTargets(bot, radius) ?: return false
|
||||
bot.attack(creatures!![RandomFunction.getRandom(creatures.size - 1)])
|
||||
return if (creatures.isNotEmpty()) {
|
||||
true
|
||||
} else {
|
||||
creatures = findTargets(bot, radius)
|
||||
if (!creatures!!.isEmpty()) {
|
||||
bot.attack(creatures[RandomFunction.getRandom(creatures.size - 1)])
|
||||
return true
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to iteratively walk a bot to a faraway location. Limited by doors and large obstacles like mountains.
|
||||
* @param loc the location to walk to.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun walkTo(loc: Location){
|
||||
if(!bot.walkingQueue.isMoving) {
|
||||
GlobalScope.launch {
|
||||
walkToIterator(loc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to iteratively walk an array of Locations to get over complex obstacles.
|
||||
* @param steps the array of locations to walk to.
|
||||
* @author dginovker
|
||||
*/
|
||||
fun walkArray(steps: Array<Location>){
|
||||
bot.pulseManager.run(object : Pulse(){
|
||||
var stepIndex = 0
|
||||
override fun pulse(): Boolean {
|
||||
// If the stepIndex is out of bounds, we're done
|
||||
if(stepIndex >= steps.size) return true
|
||||
// If we're near the last step, we're done
|
||||
if (bot.location.withinDistance(steps[steps.size - 1], 2)) {
|
||||
return true
|
||||
}
|
||||
// If we're not near the next step, walk to it
|
||||
if (!bot.location.withinDistance(steps[stepIndex], 5)) {
|
||||
walkTo(steps[stepIndex])
|
||||
return false
|
||||
}
|
||||
// If we're near the next step, increment the step index
|
||||
stepIndex++
|
||||
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loc the location to walk to.
|
||||
* @param radius tiles around the location the bot could walk to.
|
||||
* @author Kermit
|
||||
*/
|
||||
fun randomWalkTo(loc: Location, radius: Int) {
|
||||
if(!bot.walkingQueue.isMoving) {
|
||||
GlobalScope.launch {
|
||||
var newloc = loc.transform(RandomFunction.random(radius,-radius),
|
||||
RandomFunction.random(radius,-radius), 0)
|
||||
walkToIterator(newloc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The iterator for long-distance walking. Limited by doors and large obstacles like mountains.
|
||||
* @param loc the location to find a path to.
|
||||
* @author Ceikry
|
||||
*/
|
||||
private fun walkToIterator(loc: Location){
|
||||
var diffX = loc.x - bot.location.x
|
||||
var diffY = loc.y - bot.location.y
|
||||
while(!bot.location.transform(diffX, diffY, 0).withinDistance(bot.location)) {
|
||||
diffX /= 2
|
||||
diffY /= 2
|
||||
}
|
||||
GameWorld.Pulser.submit(object : MovementPulse(bot, bot.location.transform(diffX, diffY, 0), Pathfinder.SMART) {
|
||||
override fun pulse(): Boolean {
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Attacks npcs in the given radius of the bot.
|
||||
* @param bot the bot that is attacking
|
||||
* @param radius the radius to attack in
|
||||
* @param name the name of the NPC to target.
|
||||
* @return true if successfully attacking an NPC within that radius, false if not.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun attackNpcInRadius(bot: Player, name: String, radius: Int): Boolean {
|
||||
if (bot.inCombat()) return true
|
||||
var creatures: List<Entity>? = findTargets(bot, radius, name) ?: return false
|
||||
bot.attack(creatures!![RandomFunction.getRandom(creatures.size - 1)])
|
||||
return if (creatures.isNotEmpty()) {
|
||||
true
|
||||
} else {
|
||||
creatures = findTargets(bot, radius, name)
|
||||
if (!creatures!!.isEmpty()) {
|
||||
bot.attack(creatures.random())
|
||||
return true
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension function to find the distance between a location and a ground item.
|
||||
* @param loc the location to check the distance from.
|
||||
* @return a Double representing the distance.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun GroundItem.distance(loc: Location): Double{
|
||||
return location.getDistance(loc)
|
||||
}
|
||||
|
||||
/**
|
||||
* A function for teleporting the bot to the GE
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun teleportToGE() : Boolean{
|
||||
if (bot.isTeleBlocked) {
|
||||
return false
|
||||
}
|
||||
bot.lock()
|
||||
bot.visualize(ANIMATIONUP, GRAPHICSUP)
|
||||
bot.impactHandler.disabledTicks = 4
|
||||
val location = Location.create(3165, 3482, 0)
|
||||
bot.pulseManager.run(object : Pulse(4, bot) {
|
||||
override fun pulse(): Boolean {
|
||||
bot.unlock()
|
||||
bot.properties.teleportLocation = location
|
||||
bot.animator.reset()
|
||||
return true
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* A function for selling a given item on the GE.
|
||||
* @param id the ID of the item to sell on the GE. Pulls from the bot's bank.
|
||||
* @author Ceikry
|
||||
* @author Angle
|
||||
*/
|
||||
fun sellOnGE(id: Int){
|
||||
class toCounterPulse : MovementPulse(bot, Location.create(3165, 3487, 0)){
|
||||
override fun pulse(): Boolean {
|
||||
var actualId = id
|
||||
val itemAmt = bot.bank.getAmount(id)
|
||||
if (ItemDefinition.forId(id).noteId == id){
|
||||
actualId = Item(id).noteChange
|
||||
}
|
||||
val canSell = GrandExchange.addBotOffer(actualId, itemAmt)
|
||||
if (canSell && saleIsBigNews(actualId, itemAmt)) {
|
||||
SystemLogger.logAI(this::class.java, "Offered $itemAmt of $actualId on the GE.")
|
||||
Repository.sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE.")
|
||||
}
|
||||
bot.bank.remove(Item(id, itemAmt))
|
||||
bot.bank.refresh()
|
||||
return true
|
||||
}
|
||||
}
|
||||
bot.pulseManager.run(toCounterPulse())
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to sell all items in a bot's bank on the Grand Exchange, if they are tradable.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun sellAllOnGe(){
|
||||
class toCounterPulseAll : MovementPulse(bot, Location.create(3165, 3487, 0)){
|
||||
override fun pulse(): Boolean {
|
||||
for(item in bot.bank.toArray()) {
|
||||
item ?: continue
|
||||
if (item.id == Items.LOBSTER_379) continue
|
||||
if (item.id == Items.SWORDFISH_373) continue
|
||||
if (item.id == Items.SHARK_385) continue
|
||||
if(!item.definition.isTradeable) {continue}
|
||||
val itemAmt = item.amount
|
||||
var actualId = item.id
|
||||
if (ItemDefinition.forId(actualId).noteId == actualId){
|
||||
actualId = Item(actualId).noteChange
|
||||
}
|
||||
val canSell = GrandExchange.addBotOffer(actualId, itemAmt)
|
||||
if (canSell && saleIsBigNews(actualId, itemAmt)) {
|
||||
Repository.sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE.")
|
||||
}
|
||||
bot.bank.remove(item)
|
||||
bot.bank.refresh()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
bot.pulseManager.run(toCounterPulseAll())
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to sell all items in a bot's bank on the Grand Exchange, if they are tradable.
|
||||
* @author Ceikry & Kermit
|
||||
*/
|
||||
fun sellAllOnGeAdv(){
|
||||
val ge: Scenery? = getNearestNode("Desk", true) as Scenery?
|
||||
class toCounterPulseAll : MovementPulse(bot, ge, DestinationFlag.OBJECT) {
|
||||
override fun pulse(): Boolean {
|
||||
for(item in bot.bank.toArray()) {
|
||||
item ?: continue
|
||||
if(!item.definition.isTradeable) {continue}
|
||||
val itemAmt = item.amount
|
||||
var actualId = item.id
|
||||
if (ItemDefinition.forId(actualId).noteId == actualId){
|
||||
actualId = Item(actualId).noteChange
|
||||
}
|
||||
val canSell = GrandExchange.addBotOffer(actualId, itemAmt)
|
||||
if (canSell && saleIsBigNews(actualId, itemAmt)) {
|
||||
when (actualId){
|
||||
1511 -> continue
|
||||
1513 -> continue
|
||||
1515 -> continue
|
||||
1517 -> continue
|
||||
1519 -> continue
|
||||
1521 -> continue
|
||||
else -> Repository.sendNews(SERVER_GE_NAME + " just offered " + itemAmt + " " + ItemDefinition.forId(actualId).name.toLowerCase() + " on the GE.")
|
||||
}
|
||||
}
|
||||
bot.bank.remove(item)
|
||||
bot.bank.refresh()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
bot.pulseManager.run(toCounterPulseAll())
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to determine whether or not to bother everyone on the server
|
||||
* with the big news that a bot is selling something to the GE, based on item value
|
||||
* @param itemID
|
||||
* @param amount
|
||||
* @author Gexja
|
||||
*/
|
||||
fun saleIsBigNews(itemID: Int, amount: Int): Boolean {
|
||||
return ItemDefinition.forId(itemID).getAlchemyValue(true) * amount >= 500
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to teleport a bot to the given location.
|
||||
* @param loc the location to teleport to
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun teleport(loc: Location) : Boolean {
|
||||
if (bot.isTeleBlocked) {
|
||||
return false
|
||||
}
|
||||
bot.lock()
|
||||
bot.visualize(ANIMATIONUP, GRAPHICSUP)
|
||||
bot.impactHandler.disabledTicks = 4
|
||||
val location = loc
|
||||
GameWorld.Pulser.submit(object : Pulse(4, bot) {
|
||||
override fun pulse(): Boolean {
|
||||
bot.unlock()
|
||||
bot.properties.teleportLocation = location
|
||||
bot.animator.reset()
|
||||
return true
|
||||
}
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the given item out of the bot's inventory and places it into the bank. Banks all items with matching ID.
|
||||
* @param item the ID of the item to bank
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun bankItem(item: Int){
|
||||
class BankingPulse() : Pulse(20){
|
||||
override fun pulse(): Boolean {
|
||||
val logs = bot.inventory.getAmount(item)
|
||||
bot.inventory.remove(Item(item, logs))
|
||||
bot.bank.add(Item(item, logs))
|
||||
return true
|
||||
}
|
||||
}
|
||||
bot.pulseManager.run(BankingPulse())
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes every item out of the bots inventory and places it into the bank.
|
||||
* @param none
|
||||
* @author cfunnyman joe
|
||||
*/
|
||||
fun bankAll(){
|
||||
class BankingPulse() : Pulse(20){
|
||||
override fun pulse(): Boolean {
|
||||
for(item in bot.inventory.toArray()){
|
||||
var itemAmount = bot.inventory.getAmount(item)
|
||||
|
||||
bot.inventory.remove(item)
|
||||
bot.bank.add(item)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
bot.pulseManager.run(BankingPulse())
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that makes the bot eat the food item in their inventory if their HP is below 2/3.
|
||||
* @author Ceikry
|
||||
* @param foodId the ID of the food item to eat
|
||||
*/
|
||||
fun eat(foodId: Int) {
|
||||
val foodItem = Item(foodId)
|
||||
if (bot.skills.getStaticLevel(Skills.HITPOINTS) * RandomFunction.random(0.5, 0.75) >= bot.skills.lifepoints && bot.inventory.containsItem(foodItem)) {
|
||||
bot.lock(3)
|
||||
//this.animate(new Animation(829));
|
||||
val food = bot.inventory.getItem(foodItem)
|
||||
var consumable: Consumable? = Consumables.getConsumableById(foodId)
|
||||
if (consumable == null) {
|
||||
consumable = Food(intArrayOf(food.id), HealingEffect(1))
|
||||
}
|
||||
consumable.consume(food, bot)
|
||||
bot.properties.combatPulse.delayNextAttack(3)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as the eat function, except that it forces the bot to eat regardless of HP.
|
||||
* @author Ceikry
|
||||
* @param foodId the ID of the food item to eat.
|
||||
*/
|
||||
fun forceEat(foodId: Int) {
|
||||
val foodItem = Item(foodId)
|
||||
if (bot.inventory.containsItem(foodItem)) {
|
||||
bot.lock(3)
|
||||
//this.animate(new Animation(829));
|
||||
val food = bot.inventory.getItem(foodItem)
|
||||
var consumable: Consumable? = Consumables.getConsumableById(foodId)
|
||||
if (consumable == null) {
|
||||
consumable = Food(intArrayOf(foodId), HealingEffect(1))
|
||||
}
|
||||
consumable.consume(food, bot)
|
||||
bot.properties.combatPulse.delayNextAttack(3)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for buying items off the GE.
|
||||
* @param itemID the id of the item to buy off the GE.
|
||||
* @param amount the amount to buy.
|
||||
* @return true if item was successfully bought, false if not.
|
||||
*/
|
||||
fun buyFromGE(bot: Player, itemID: Int, amount: Int){
|
||||
GlobalScope.launch {
|
||||
val offer = GrandExchangeOffer()
|
||||
offer.itemID = itemID
|
||||
offer.sell = false
|
||||
offer.offeredValue = checkPriceOverrides(itemID) ?: ItemDefinition.forId(itemID).value
|
||||
offer.amount = amount
|
||||
offer.player = bot
|
||||
//GrandExchange.dispatch(bot, offer)
|
||||
AIRepository.addOffer(bot, offer)
|
||||
var bought: Boolean = false
|
||||
val latch = CountDownLatch(1)
|
||||
bot.pulseManager.run(object : Pulse(5) {
|
||||
override fun pulse(): Boolean {
|
||||
bought = offer.completedAmount == offer.amount
|
||||
latch.countDown()
|
||||
return true
|
||||
}
|
||||
})
|
||||
latch.await()
|
||||
if(bought){
|
||||
bot.bank.add(Item(offer.itemID, offer.completedAmount))
|
||||
bot.bank.refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to allow a bot to withdraw items from its bank.
|
||||
* @param itemID the item to withdraw.
|
||||
* @param amount the amount to withdraw.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun withdraw(itemID: Int, amount: Int){
|
||||
var item: Item? = null
|
||||
if(bot.bank.containsItem(Item(itemID, amount))){
|
||||
item = Item(itemID, amount)
|
||||
} else {
|
||||
item = Item(itemID, bot.bank.getAmount(itemID))
|
||||
}
|
||||
if(item.amount == 0) return
|
||||
if(!bot.inventory.hasSpaceFor(item)){
|
||||
item.amount = bot.inventory.getMaximumAdd(item)
|
||||
}
|
||||
bot.bank.remove(item)
|
||||
bot.inventory.add(item)
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to equip list of items and set stats
|
||||
* Useful for starting a bot up
|
||||
* @param items the list of items to equip
|
||||
* @author dginovker
|
||||
*/
|
||||
fun equipAndSetStats(items: List<Item>?){
|
||||
if (items == null) return
|
||||
for(item in items){
|
||||
equipAndSetStats(item)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to equip a single item and set stats
|
||||
* Useful for starting a bot up
|
||||
* @param item the item to equip
|
||||
* @author dginovker
|
||||
*/
|
||||
fun equipAndSetStats(item: Item){
|
||||
val configs = item.definition.handlers
|
||||
val slot = configs["equipment_slot"] ?: return
|
||||
bot.equipment.add(item, slot as Int,
|
||||
false,false)
|
||||
val reqs = configs["requirements"]
|
||||
if(reqs != null)
|
||||
for(req in configs["requirements"] as HashMap<Int,Int>)
|
||||
bot.skills.setStaticLevel(req.key, req.value)
|
||||
bot.skills.updateCombatLevel()
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to load appearance and equipment from JSON
|
||||
* Useful for starting a bot up
|
||||
* @param json the JSON object to load from (dumped via ::dumpappearance)
|
||||
* @author dginovker
|
||||
*/
|
||||
fun loadAppearanceAndEquipment(json: JSONObject?) {
|
||||
if (json == null) return
|
||||
bot.equipment.clear()
|
||||
bot.appearance.parse(json["appearance"] as JSONObject)
|
||||
val equipment = json["equipment"] as JSONArray
|
||||
bot.equipment.parse(equipment)
|
||||
bot.appearance.sync()
|
||||
for (i in 0 until bot.equipment.capacity()) {
|
||||
val item = bot.equipment.get(i)
|
||||
if (item != null) {
|
||||
equipAndSetStats(item)
|
||||
}
|
||||
}
|
||||
// Set all combat stats to a function of the highest combat stat(otherwise you end up with lopsided stats)
|
||||
val highestCombatSkill = bot.skills.getStaticLevel(bot.skills.highestCombatSkillId)
|
||||
for (i in 0 until 7) {
|
||||
bot.skills.setStaticLevel(i, max((highestCombatSkill * 0.75).toInt(), bot.skills.getStaticLevel(i)))
|
||||
}
|
||||
bot.skills.updateCombatLevel()
|
||||
}
|
||||
|
||||
fun getOverlay(): BottingOverlay {
|
||||
return BottingOverlay(bot)
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to check for price overrides.
|
||||
* @param id the id to check for overrides for.
|
||||
* @author Ceikry
|
||||
*/
|
||||
fun checkPriceOverrides(id: Int): Int?{
|
||||
return when(id){
|
||||
else -> itemDefinition(id).getConfiguration(ItemConfigParser.GE_PRICE)
|
||||
}
|
||||
}
|
||||
|
||||
class BottingOverlay(val player: Player){
|
||||
fun init(){
|
||||
player.interfaceManager.openOverlay(Component(195))
|
||||
player.packetDispatch.sendInterfaceConfig(195,5,true)
|
||||
}
|
||||
fun setTitle(title: String){
|
||||
player.packetDispatch.sendString(colorize("%B$title"),195,7)
|
||||
}
|
||||
fun setTaskLabel(label: String){
|
||||
player.packetDispatch.sendString(colorize("%B$label"),195,8)
|
||||
}
|
||||
fun setAmount(amount: Int){
|
||||
player.packetDispatch.sendString(colorize("%B$amount"),195,9)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package core.game.bots
|
||||
|
||||
annotation class ScriptDescription(vararg val value: String)
|
||||
@@ -0,0 +1,3 @@
|
||||
package core.game.bots
|
||||
|
||||
annotation class ScriptIdentifier(val value: String)
|
||||
@@ -0,0 +1,3 @@
|
||||
package core.game.bots
|
||||
|
||||
annotation class ScriptName(val value: String)
|
||||
@@ -0,0 +1,44 @@
|
||||
package core.game.bots
|
||||
|
||||
import core.game.node.item.Item
|
||||
import core.game.world.map.Location
|
||||
|
||||
class SkillingBotAssembler {
|
||||
fun produce(type: Wealth, loc: Location): AIPlayer {
|
||||
return assembleBot(AIPlayer(loc),type)
|
||||
}
|
||||
|
||||
fun assembleBot(bot: AIPlayer, type: Wealth): AIPlayer {
|
||||
return when(type){
|
||||
Wealth.POOR -> equipSet(bot,POORSETS.random())
|
||||
Wealth.AVERAGE -> equipSet(bot,AVGSETS.random())
|
||||
Wealth.RICH -> equipSet(bot,RICHSETS.random())
|
||||
}
|
||||
}
|
||||
|
||||
fun equipSet(bot: AIPlayer, set: List<Int>): AIPlayer {
|
||||
for(i in set){
|
||||
val item = Item(i)
|
||||
val configs = item.definition.handlers
|
||||
val slot = configs["equipment_slot"] ?: continue
|
||||
bot.equipment.add(item, slot as Int,
|
||||
false,false)
|
||||
val reqs = configs["requirements"]
|
||||
if(reqs != null)
|
||||
for(req in configs["requirements"] as HashMap<Int,Int>)
|
||||
bot.skills.setStaticLevel(req.key, req.value)
|
||||
}
|
||||
bot.skills.updateCombatLevel()
|
||||
return bot
|
||||
}
|
||||
|
||||
enum class Wealth {
|
||||
POOR,
|
||||
AVERAGE,
|
||||
RICH
|
||||
}
|
||||
|
||||
val POORSETS = arrayOf(listOf(542,544), listOf(581), listOf(6654,6655,6656), listOf(6654,6656), listOf(636,646), listOf(638,648), listOf(), listOf(), listOf())
|
||||
val AVGSETS = arrayOf(listOf(2649,342,344), listOf(2651,542,544), listOf(6654,6655,6656), listOf(6139,6141), listOf(9923,9924,9925), listOf(10400,10402,2649), listOf(10404,10406), listOf(12971,12978))
|
||||
val RICHSETS = arrayOf(listOf(10330,10332,2649), listOf(12873,12880,1046), listOf(13858,13861,13864), listOf(13887,13893), listOf(3481,3483), listOf(2653,2655), listOf(2661,2663), listOf(2591,2593), listOf(14490,14492))
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package core.game.component;
|
||||
|
||||
import core.game.node.entity.player.Player;
|
||||
|
||||
/**
|
||||
* An event called when the interface gets closed.
|
||||
* @author Emperor
|
||||
*/
|
||||
public interface CloseEvent {
|
||||
|
||||
/**
|
||||
* Called when the interface gets closed.
|
||||
* @param player The player.
|
||||
* @param c The component.
|
||||
* @return {@code True} if successful, {@code false} if the component should
|
||||
* remain open.
|
||||
*/
|
||||
boolean close(Player player, Component c);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package core.game.component;
|
||||
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.game.node.entity.player.link.InterfaceManager;
|
||||
import core.net.packet.PacketRepository;
|
||||
import core.net.packet.context.InterfaceContext;
|
||||
import core.net.packet.out.Interface;
|
||||
import core.game.interaction.InterfaceListeners;
|
||||
|
||||
/**
|
||||
* Represents a component.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public class Component {
|
||||
|
||||
/**
|
||||
* The component id.
|
||||
*/
|
||||
protected int id;
|
||||
|
||||
/**
|
||||
* The component definitions.
|
||||
*/
|
||||
protected final ComponentDefinition definition;
|
||||
|
||||
/**
|
||||
* The close event.
|
||||
*/
|
||||
protected CloseEvent closeEvent;
|
||||
|
||||
/**
|
||||
* The component plugin.
|
||||
*/
|
||||
protected ComponentPlugin plugin;
|
||||
|
||||
/**
|
||||
* If the component is hidden.
|
||||
*/
|
||||
private boolean hidden;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Component} {@code Object}.
|
||||
* @param id The component id.
|
||||
*/
|
||||
public Component(int id) {
|
||||
this.id = id;
|
||||
this.definition = ComponentDefinition.forId(id);
|
||||
this.plugin = definition.getPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the component.
|
||||
*/
|
||||
public void open(Player player) {
|
||||
InterfaceManager manager = player.getInterfaceManager();
|
||||
InterfaceListeners.runOpen(player,this);
|
||||
if (definition == null) {
|
||||
PacketRepository.send(Interface.class, new InterfaceContext(player, manager.getWindowPaneId(), manager.getDefaultChildId(), getId(), false));
|
||||
if (plugin != null) {
|
||||
plugin.open(player, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (definition.getType() == InterfaceType.WINDOW_PANE) {
|
||||
return;
|
||||
}
|
||||
if (definition.getType() == InterfaceType.TAB) {
|
||||
PacketRepository.send(Interface.class, new InterfaceContext(player, definition.getWindowPaneId(manager.isResizable()), definition.getChildId(manager.isResizable()) + definition.getTabIndex(), getId(), definition.isWalkable()));
|
||||
if (plugin != null) {
|
||||
plugin.open(player, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
PacketRepository.send(Interface.class, new InterfaceContext(player, definition.getWindowPaneId(manager.isResizable()), definition.getChildId(manager.isResizable()), getId(), definition.isWalkable()));
|
||||
if (plugin != null) {
|
||||
plugin.open(player, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the component.
|
||||
* @param player The player.
|
||||
* @return {@code True} if the component can be closed.
|
||||
*/
|
||||
public boolean close(Player player) {
|
||||
return (closeEvent == null || closeEvent.close(player, this)) && InterfaceListeners.runClose(player, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id.
|
||||
* @return The id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the definition.
|
||||
* @return The definition.
|
||||
*/
|
||||
public ComponentDefinition getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the closeEvent.
|
||||
* @return The closeEvent.
|
||||
*/
|
||||
public CloseEvent getCloseEvent() {
|
||||
return closeEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the closeEvent.
|
||||
* @param closeEvent The closeEvent to set.
|
||||
*/
|
||||
public Component setCloseEvent(CloseEvent closeEvent) {
|
||||
this.closeEvent = closeEvent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the component unclosable.
|
||||
* @param c The component.
|
||||
*/
|
||||
public static void setUnclosable(Player p, Component c) {
|
||||
p.setAttribute("close_c_", true);
|
||||
c.setCloseEvent(new CloseEvent() {
|
||||
@Override
|
||||
public boolean close(Player player, Component c) {
|
||||
return !player.getAttribute("close_c_", false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the plugin.
|
||||
* @param plugin the plugin.
|
||||
*/
|
||||
public void setPlugin(ComponentPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the component plugin.
|
||||
* @return the plugin.
|
||||
*/
|
||||
public ComponentPlugin getPlugin() {
|
||||
if (plugin == null) {
|
||||
ComponentPlugin p = ComponentDefinition.forId(getId()).getPlugin();
|
||||
if ((plugin = p) != null) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hidden value.
|
||||
* @return The hidden.
|
||||
*/
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hidden value.
|
||||
* @param hidden The hidden to set.
|
||||
*/
|
||||
public void setHidden(boolean hidden) {
|
||||
this.hidden = hidden;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package core.game.component;
|
||||
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents the component definitions.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class ComponentDefinition {
|
||||
|
||||
/**
|
||||
* The component definitions mapping.
|
||||
*/
|
||||
private static final Map<Integer, ComponentDefinition> DEFINITIONS = new HashMap<Integer, ComponentDefinition>();
|
||||
|
||||
/**
|
||||
* The interface type.
|
||||
*/
|
||||
private InterfaceType type = InterfaceType.DEFAULT;
|
||||
|
||||
/**
|
||||
* The interface context.
|
||||
*/
|
||||
private boolean walkable;
|
||||
|
||||
/**
|
||||
* The tab index.
|
||||
*/
|
||||
private int tabIndex = -1;
|
||||
|
||||
/**
|
||||
* Represents the plugin handler.
|
||||
*/
|
||||
private ComponentPlugin plugin;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ComponentDefinition} {@code Object}.
|
||||
*/
|
||||
public ComponentDefinition() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the definition values from a result set.
|
||||
* @throws SQLException The exception if thrown.
|
||||
*/
|
||||
public ComponentDefinition parse(String type, String walkable, String tabIndex){
|
||||
setType(InterfaceType.values()[Integer.parseInt(type)]);
|
||||
setWalkable(Boolean.parseBoolean(walkable));
|
||||
setTabIndex(Integer.parseInt(tabIndex));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the component definitions for the component id.
|
||||
* @param componentId The component id.
|
||||
* @return The component definitions.
|
||||
*/
|
||||
public static ComponentDefinition forId(int componentId) {
|
||||
ComponentDefinition def = DEFINITIONS.get(componentId);
|
||||
if (def == null) {
|
||||
DEFINITIONS.put(componentId, def = new ComponentDefinition());
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a plugin to a definition.
|
||||
* @param id the id.
|
||||
* @param plugin the plugin.
|
||||
*/
|
||||
public static void put(int id, ComponentPlugin plugin) {
|
||||
ComponentDefinition.forId(id).setPlugin(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the definitions mapping.
|
||||
* @return The definitions mapping.
|
||||
*/
|
||||
public static Map<Integer, ComponentDefinition> getDefinitions() {
|
||||
return DEFINITIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugin.
|
||||
* @return The plugin.
|
||||
*/
|
||||
public ComponentPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the plugin.
|
||||
* @param plugin The plugin to set.
|
||||
*/
|
||||
public void setPlugin(ComponentPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the window pane id.
|
||||
* @param resizable If the player is using resizable mode.
|
||||
* @return The window pane id.
|
||||
*/
|
||||
public int getWindowPaneId(boolean resizable) {
|
||||
return resizable ? type.getResizablePaneId() : type.getFixedPaneId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the child id.
|
||||
* @param resizable If the player is using resizable mode.
|
||||
* @return The child id.
|
||||
*/
|
||||
public int getChildId(boolean resizable) {
|
||||
return resizable ? type.getResizableChildId() : type.getFixedChildId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type.
|
||||
* @return the type
|
||||
*/
|
||||
public InterfaceType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the batype.
|
||||
* @param type the type to set.
|
||||
*/
|
||||
public void setType(InterfaceType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the walkable.
|
||||
* @return the walkable
|
||||
*/
|
||||
public boolean isWalkable() {
|
||||
return walkable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bawalkable.
|
||||
* @param walkable the walkable to set.
|
||||
*/
|
||||
public void setWalkable(boolean walkable) {
|
||||
this.walkable = walkable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tabIndex.
|
||||
* @return the tabIndex
|
||||
*/
|
||||
public int getTabIndex() {
|
||||
return tabIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the batabIndex.
|
||||
* @param tabIndex the tabIndex to set.
|
||||
*/
|
||||
public void setTabIndex(int tabIndex) {
|
||||
this.tabIndex = tabIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ComponentDefinition [type=" + type + ", walkable=" + walkable + ", tabIndex=" + tabIndex + ", plugin=" + plugin + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package core.game.component;
|
||||
|
||||
import core.game.node.entity.player.Player;
|
||||
import core.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Represents the plugin used to handle a component reward.
|
||||
* @author Vexia
|
||||
*/
|
||||
public abstract class ComponentPlugin implements Plugin<Object> {
|
||||
|
||||
/**
|
||||
* Handles the interface interaction.
|
||||
* @param player The player.
|
||||
* @param component The component.
|
||||
* @param opcode The opcode.
|
||||
* @param slot The slot.
|
||||
* @param itemId The item id.
|
||||
* @return {@code True} if succesfully handled.
|
||||
*/
|
||||
public abstract boolean handle(final Player player, Component component, final int opcode, final int button, int slot, int itemId);
|
||||
|
||||
/**
|
||||
* Called when this component opens.
|
||||
* @param player The player
|
||||
* @param component The component opening.
|
||||
*/
|
||||
public void open(Player player, Component component) {}
|
||||
|
||||
@Override
|
||||
public Object fireEvent(String identifier, Object... args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user