Refactored components of the ScriptAPI to more efficiently utilize pathfinding

Implemented a global limit on pathfinding distance (server.max_pathfind_dist)
Pathfinding limit is enforced at the packet level as well as elsewhere (ContentAPI, etc)
This commit is contained in:
Ceikry
2023-04-24 14:16:59 +00:00
committed by Ryan
parent 5aded2b349
commit 4b20cdd001
15 changed files with 369 additions and 326 deletions
+1 -1
View File
@@ -285,7 +285,7 @@ exceptions:
- 'Throwable'
allowedExceptionNameRegex: '_|(ignore|expected).*'
TooGenericExceptionThrown:
active: true
active: false
exceptionNames:
- 'Error'
- 'Exception'
@@ -97,9 +97,9 @@ class LobsterCatcher : Script() {
state = State.FISHING
} else {
if (bot.location.x < 2837) {
Pathfinder.find(bot, Location.create(2837, 3435, 0)).walk(bot)
scriptAPI.walkTo(Location.create(2837, 3435, 0))
} else {
Pathfinder.find(bot, Location.create(2854, 3427, 0)).walk(bot)
scriptAPI.walkTo(Location.create(2854, 3427, 0))
}
}
}
@@ -194,4 +194,4 @@ class LobsterCatcher : Script() {
}
return newInstance()
}
}
}
+202 -199
View File
@@ -13,270 +13,273 @@ import java.math.BigInteger
* @author Ceikry
*/
class ServerConstants {
companion object {
var NOAUTH_DEFAULT_ADMIN: Boolean = true
companion object {
var NOAUTH_DEFAULT_ADMIN: Boolean = true
@JvmField
var DAILY_ACCOUNT_LIMIT = 3
var DAILY_ACCOUNT_LIMIT = 3
@JvmField
var REVENANT_POPULATION: Int = 30
var REVENANT_POPULATION: Int = 30
@JvmField
var BOTS_INFLUENCE_PRICE_INDEX = true
var BOTS_INFLUENCE_PRICE_INDEX = true
@JvmField
var SHUTDOWN_HOOK: Thread = Thread(SystemShutdownHook())
@JvmField
var ALLOW_GUI: Boolean = false
var SHUTDOWN_HOOK: Thread = Thread(SystemShutdownHook())
@JvmField
var DATA_PATH: String? = null
var ALLOW_GUI: Boolean = false
//path to the cache
@JvmField
var CACHE_PATH: String? = null
@JvmField
var DATA_PATH: String? = null
//path for the server store
@JvmField
var STORE_PATH: String? = null
//path to the cache
@JvmField
var CACHE_PATH: String? = null
//path for player saves
@JvmField
var PLAYER_SAVE_PATH: String? = null
//path for the server store
@JvmField
var STORE_PATH: String? = null
@JvmField
var PLAYER_ATTRIBUTE_PATH = "ish";
//path for player saves
@JvmField
var PLAYER_SAVE_PATH: String? = null
//path to the various config files, such as npc_spawns.json
var CONFIG_PATH: String? = null
@JvmField
var PLAYER_ATTRIBUTE_PATH = "ish";
@JvmField
var GRAND_EXCHANGE_DATA_PATH: String? = null
//path to the various config files, such as npc_spawns.json
var CONFIG_PATH: String? = null
@JvmField
var RDT_DATA_PATH: String? = null
@JvmField
var GRAND_EXCHANGE_DATA_PATH: String? = null
@JvmField
var OBJECT_PARSER_PATH: String? = null
@JvmField
var RDT_DATA_PATH: String? = null
@JvmField
var SCRIPTS_PATH: String? = null
@JvmField
var OBJECT_PARSER_PATH: String? = null
@JvmField
var DIALOGUE_SCRIPTS_PATH: String? = null
@JvmField
var SCRIPTS_PATH: String? = null
@JvmField
var LOGS_PATH: String? = null
@JvmField
var DIALOGUE_SCRIPTS_PATH: String? = null
@JvmField
var BOT_DATA_PATH: String? = null
@JvmField
var LOGS_PATH: String? = null
@JvmField
var CELEDT_DATA_PATH: String? = null
@JvmField
var BOT_DATA_PATH: String? = null
@JvmField
var USDT_DATA_PATH: String? = null
@JvmField
var CELEDT_DATA_PATH: String? = null
@JvmField
var HDT_DATA_PATH: String? = null
@JvmField
var USDT_DATA_PATH: String? = null
@JvmField
var GDT_DATA_PATH: String? = null
@JvmField
var HDT_DATA_PATH: String? = null
@JvmField
var RSDT_DATA_PATH: String? = null
@JvmField
var GDT_DATA_PATH: String? = null
@JvmField
var ASDT_DATA_PATH: String? = null
@JvmField
var RSDT_DATA_PATH: String? = null
//the max number of players.
@JvmField
var MAX_PLAYERS = 2000
@JvmField
var ASDT_DATA_PATH: String? = null
//the max number of NPCs
@JvmField
var MAX_NPCS = 32000
//the max number of players.
@JvmField
var MAX_PLAYERS = 2000
//the location where new players are placed on login.
@JvmField
var START_LOCATION: Location? = null
//the max number of NPCs
@JvmField
var MAX_NPCS = 32000
//Location for all home teleports/respawn location
@JvmField
var HOME_LOCATION: Location? = null
//the location where new players are placed on login.
@JvmField
var START_LOCATION: Location? = null
//the name for the database
@JvmField
var DATABASE_NAME: String? = null
//Location for all home teleports/respawn location
@JvmField
var HOME_LOCATION: Location? = null
//username for the database
@JvmField
var DATABASE_USER: String? = null
//the name for the database
@JvmField
var DATABASE_NAME: String? = null
//password for the database
@JvmField
var DATABASE_PASS: String? = null
//username for the database
@JvmField
var DATABASE_USER: String? = null
//address for the database
@JvmField
var DATABASE_ADDRESS: String? = null
//password for the database
@JvmField
var DATABASE_PASS: String? = null
@JvmField
var DATABASE_PORT: String? = null
//address for the database
@JvmField
var DATABASE_ADDRESS: String? = null
@JvmField
var WRITE_LOGS: Boolean = false
@JvmField
var DATABASE_PORT: String? = null
@JvmField
var BANK_SIZE: Int = 496
@JvmField
var WRITE_LOGS: Boolean = false
@JvmField
var BANK_BOOTH_QUICK_OPEN: Boolean = false
@JvmField
var BANK_SIZE: Int = 496
@JvmField
var BANK_BOOTH_NOTE_ENABLED: Boolean = true
@JvmField
var BANK_BOOTH_QUICK_OPEN: Boolean = false
@JvmField
var BANK_BOOTH_NOTE_UIM: Boolean = true
@JvmField
var BANK_BOOTH_NOTE_ENABLED: Boolean = true
@JvmField
var GE_AUTOSAVE_FREQUENCY = secondsToTicks(3600) //1 hour
@JvmField
var BANK_BOOTH_NOTE_UIM: Boolean = true
@JvmField
var GE_AUTOSTOCK_ENABLED = false
@JvmField
var GE_AUTOSAVE_FREQUENCY = secondsToTicks(3600) //1 hour
@JvmField
var MS_SECRET_KEY = ""
@JvmField
var GE_AUTOSTOCK_ENABLED = false
@JvmField
var LOG_CUTSCENE = true
@JvmField
var MS_SECRET_KEY = ""
@JvmField
var RULES_AND_INFO_ENABLED = true
@JvmField
var LOG_CUTSCENE = true
@JvmField
var WATCHDOG_ENABLED = true
@JvmField
var RULES_AND_INFO_ENABLED = true
@JvmField
var I_AM_A_CHEATER = false
@JvmField
var WATCHDOG_ENABLED = true
@JvmField
var LOG_LEVEL = LogLevel.VERBOSE
@JvmField
var I_AM_A_CHEATER = false
@JvmField
var JAVA_VERSION = 8
@JvmField
var LOG_LEVEL = LogLevel.VERBOSE
//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(CastleWars.lobbyBankArea.randomLoc, "cwars", "castle wars", "castle war", "castlewars", "castlewar", "castle")
)
@JvmField
var JAVA_VERSION = 8
@JvmField
var DATABASE: Database? = null
//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(CastleWars.lobbyBankArea.randomLoc, "cwars", "castle wars", "castle war", "castlewars", "castlewar", "castle")
)
//if SQL is enabled
@JvmField
var MYSQL = true
@JvmField
var DATABASE: Database? = null
//the server name
@JvmField
var SERVER_NAME: String = ""
//if SQL is enabled
@JvmField
var MYSQL = true
//the server's grand exchange name
@JvmField
var SERVER_GE_NAME: String = ""
//the server name
@JvmField
var SERVER_NAME: String = ""
//The RSA_KEY for the server.
@JvmField
var EXPONENT = BigInteger("52317200263721308660411803146360972546561037484450290559823448967617618536819222494429186211525706853703641369936136465589036631055945454547936148730495933263344792588795811788941129493188907621550836988152620502378278134421731002382361670176785306598134280732756356458964850508114958769985438054979422820241")
//the server's grand exchange name
@JvmField
var SERVER_GE_NAME: String = ""
//The MODULUS for the server.
@JvmField
var MODULUS = BigInteger("96982303379631821170939875058071478695026608406924780574168393250855797534862289546229721580153879336741968220328805101128831071152160922518190059946555203865621183480223212969502122536662721687753974815205744569357388338433981424032996046420057284324856368815997832596174397728134370577184183004453899764051")
//The RSA_KEY for the server.
@JvmField
var EXPONENT = BigInteger("52317200263721308660411803146360972546561037484450290559823448967617618536819222494429186211525706853703641369936136465589036631055945454547936148730495933263344792588795811788941129493188907621550836988152620502378278134421731002382361670176785306598134280732756356458964850508114958769985438054979422820241")
@JvmField
var DAILY_RESTART = false
//The MODULUS for the server.
@JvmField
var MODULUS = BigInteger("96982303379631821170939875058071478695026608406924780574168393250855797534862289546229721580153879336741968220328805101128831071152160922518190059946555203865621183480223212969502122536662721687753974815205744569357388338433981424032996046420057284324856368815997832596174397728134370577184183004453899764051")
@JvmField
var DISCORD_GE_WEBHOOK = ""
@JvmField
var DAILY_RESTART = false
@JvmField
var DISCORD_MOD_WEBHOOK = ""
@JvmField
var DISCORD_GE_WEBHOOK = ""
@JvmField
var DISCORD_OPENRSC_HOOK = ""
@JvmField
var DISCORD_MOD_WEBHOOK = ""
@JvmField
var PRELOAD_MAP = false
@JvmField
var DISCORD_OPENRSC_HOOK = ""
@JvmField
var USE_AUTH = false
@JvmField
var PRELOAD_MAP = false
@JvmField
var PERSIST_ACCOUNTS = false
@JvmField
var USE_AUTH = false
@JvmField
var DRAGON_AXE_USE_OSRS_SPEC = false
@JvmField
var PERSIST_ACCOUNTS = false
@JvmField
var ENABLE_GLOBALCHAT = false
}
@JvmField
var DRAGON_AXE_USE_OSRS_SPEC = false
@JvmField
var ENABLE_GLOBALCHAT = false
@JvmField
var MAX_PATHFIND_DISTANCE = 25
}
}
+8 -4
View File
@@ -70,8 +70,10 @@ import core.game.world.repository.Repository
import core.game.consumable.*
import core.tools.Log
import core.tools.tick
import core.ServerConstants
import core.api.utils.Vector
import java.util.regex.*
import kotlin.math.absoluteValue
import kotlin.math.*
/**
* Gets a skilling tool which the player has the level to use and is in their inventory.
@@ -1770,15 +1772,17 @@ fun getServerConfig(): Toml {
}
fun getPathableRandomLocalCoordinate(target: Entity, radius: Int, center: Location, maxAttempts: Int = 3): Location {
val swCorner = center.transform(-radius, -radius, center.z)
val neCorner = center.transform(radius, radius, center.z)
var maxRadius = Vector.deriveWithEqualComponents(ServerConstants.MAX_PATHFIND_DISTANCE.toDouble()).x - 1
var effectiveRadius = min(radius, maxRadius.toInt())
val swCorner = center.transform(-effectiveRadius, -effectiveRadius, center.z)
val neCorner = center.transform(effectiveRadius, effectiveRadius, center.z)
val borders = ZoneBorders(swCorner.x, swCorner.y, neCorner.x, neCorner.y, center.z)
var attempts = maxAttempts
var success: Boolean
while (attempts-- > 0) {
val dest = borders.randomLoc
val path = Pathfinder.find(target, dest)
val path = Pathfinder.find(center, dest, target.size())
success = path.isSuccessful && !path.isMoveNear
if (success) return dest
}
+20
View File
@@ -25,11 +25,31 @@ class Vector (val x: Double, val y: Double) {
return Vector(this.x * other, this.y * other)
}
operator fun plus (other: Vector) : Vector {
return Vector(this.x + other.x, this.y + other.y)
}
operator fun minus (other: Vector) : Vector {
return Vector(this.x - other.x, this.y - other.y)
}
override fun toString() : String {
return "{$x,$y}"
}
fun invert() : Vector {
return -this
}
companion object {
@JvmStatic fun betweenLocs (from: Location, to: Location) : Vector {
val xDiff = to.x - from.x
val yDiff = to.y - from.y
return Vector (xDiff.toDouble(), yDiff.toDouble())
}
@JvmStatic fun deriveWithEqualComponents (magnitude: Double) : Vector {
var sideLength = sqrt(magnitude.pow(2.0) / 2)
return Vector(sideLength, sideLength)
}
}
}
@@ -40,7 +40,7 @@ class GeneralBotCreator {
randomDelay -= 1
return false
}
if (!botScript.bot.pulseManager.hasPulseRunning()) {
if (!botScript.bot.pulseManager.hasPulseRunning() && botScript.bot.scripts.getActiveScript() == null) {
/*if (ticks++ >= RandomFunction.random(90000,120000)) {
AIPlayer.deregister(botScript.bot.uid)
@@ -77,4 +77,4 @@ class GeneralBotCreator {
return true
}
}
}
}
+62 -107
View File
@@ -49,6 +49,8 @@ import java.util.concurrent.CountDownLatch
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.sqrt
import core.ServerConstants
import core.api.utils.Vector
class ScriptAPI(private val bot: Player) {
val GRAPHICSUP = Graphics(1576)
@@ -86,24 +88,6 @@ class ScriptAPI(private val bot: Player) {
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)))
@@ -115,33 +99,11 @@ class ScriptAPI(private val bot: Player) {
* @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
}
if (isObject)
return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].objectList, acceptedName = acceptedNames)
else
return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities, acceptedName = acceptedNames)
}
/**
@@ -151,30 +113,21 @@ class ScriptAPI(private val bot: Player) {
* @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
}
fun getNearestNode(id: Int, isObject: Boolean): Node? {
if (isObject)
return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].objectList, acceptedId = id)
else
return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities, acceptedId = id)
}
/**
* 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? {
return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities, acceptedName = listOf(entityName))
}
/**
@@ -184,30 +137,38 @@ class ScriptAPI(private val bot: Player) {
* @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)
}
}
fun getNearestNode(name: String, isObject: Boolean): Node? {
if (isObject)
return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].objectList, acceptedName = listOf(name))
else
return processEvaluationList(RegionManager.forId(bot.location.regionId).planes[bot.location.z].entities, acceptedName = listOf(name))
}
fun evaluateViability (e: Node?, minDistance: Double, maxDistance: Double, acceptedNames: List<String>? = null, acceptedId: Int = -1): Boolean {
if (e == null || !e.isActive)
return false
if (acceptedId != -1 && e.id != acceptedId)
return false
val dist = distance(bot, e)
if (dist > maxDistance || dist > minDistance)
return false
val name = e?.name
return (acceptedNames?.contains(name) ?: true && !Pathfinder.find(bot, e).isMoveNear)
}
fun processEvaluationList (list: List<Node>, acceptedName: List<String>? = null, acceptedId: Int = -1): Node? {
var entity: Node? = null
var minDistance = Double.MAX_VALUE
val maxDistance = ServerConstants.MAX_PATHFIND_DISTANCE.toDouble()
for (e in list) {
if (evaluateViability(e, minDistance, maxDistance, acceptedName, acceptedId)) {
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
}
return entity
}
/**
@@ -350,9 +311,7 @@ class ScriptAPI(private val bot: Player) {
*/
fun walkTo(loc: Location){
if(!bot.walkingQueue.isMoving) {
GlobalScope.launch {
walkToIterator(loc)
}
walkToIterator(loc)
}
}
@@ -391,11 +350,8 @@ class ScriptAPI(private val bot: Player) {
*/
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)
}
var newloc = loc.transform(RandomFunction.random(radius,-radius),RandomFunction.random(radius,-radius), 0)
walkToIterator(newloc)
}
}
@@ -408,15 +364,12 @@ class ScriptAPI(private val bot: Player) {
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
}
})
val vec = Vector.betweenLocs(bot.location, loc)
val norm = vec.normalized()
val tiles = kotlin.math.min(kotlin.math.floor(vec.magnitude()).toInt(), ServerConstants.MAX_PATHFIND_DISTANCE - 1)
val loc = bot.location.transform(norm * tiles)
bot.pulseManager.run(object : MovementPulse(bot, loc) { override fun pulse() : Boolean { return true } })
}
/**
@@ -469,6 +422,7 @@ class ScriptAPI(private val bot: Player) {
override fun pulse(): Boolean {
bot.unlock()
bot.properties.teleportLocation = location
bot.pulseManager.clear()
bot.animator.reset()
return true
}
@@ -599,6 +553,7 @@ class ScriptAPI(private val bot: Player) {
override fun pulse(): Boolean {
bot.unlock()
bot.properties.teleportLocation = location
bot.pulseManager.clear()
bot.animator.reset()
return true
}
@@ -78,6 +78,8 @@ public abstract class MovementPulse extends Pulse {
private Function2<Entity,Node,Location> overrideMethod;
private Location previousLoc;
/**
* Constructs a new {@code MovementPulse} {@code Object}.
*
@@ -263,7 +265,7 @@ public abstract class MovementPulse extends Pulse {
else if (inside) {
loc = findBorderLocation();
}
}
} else if (loc == previousLoc) return;
if (destination == null) {
return;
@@ -293,6 +295,7 @@ public abstract class MovementPulse extends Pulse {
}
Path path = Pathfinder.find(mover, loc != null ? loc : destination, true, pathfinder);
loc = destination.getLocation();
near = !path.isSuccessful() || path.isMoveNear();
interactLocation = mover.getLocation();
boolean canMove = true;
@@ -330,6 +333,7 @@ public abstract class MovementPulse extends Pulse {
}
}
}
previousLoc = loc;
}
last = destination.getLocation();
}
@@ -45,11 +45,11 @@ class ScriptProcessor(val entity: Entity) {
if (entity !is Player) return
if (!entity.delayed() && canProcess && interactTarget != null) {
if (opScript != null && inOperableDistance()) {
face(entity, interactTarget?.centerLocation ?: return)
face(entity, interactTarget?.getFaceLocation(entity.location) ?: return)
processInteractScript(opScript ?: return)
}
else if (apScript != null && inApproachDistance(apScript ?: return)) {
face(entity, interactTarget?.centerLocation ?: return)
face(entity, interactTarget?.getFaceLocation(entity.location) ?: return)
processInteractScript(apScript ?: return)
}
else if (apScript == null && opScript == null && inOperableDistance()) {
+17 -1
View File
@@ -9,6 +9,7 @@ import core.game.node.scenery.Scenery;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.tools.StringUtils;
import core.api.utils.Vector;
/**
* Represents a node which is anything that is interactable in Keldagrim.
@@ -120,6 +121,21 @@ public abstract class Node {
return location.transform(offset, offset, 0);
}
public Vector getMathematicalCenter() {
Location topRight = location.transform(size - 1, size - 1, 0);
double x = ((double) location.getX() + (double) topRight.getX()) / 2.0;
double y = ((double) location.getY() + (double) topRight.getY()) / 2.0;
return new Vector(x, y);
}
public Location getFaceLocation (Location fromLoc) {
Vector center = getMathematicalCenter();
Vector fromVec = new Vector((double) fromLoc.getX(), (double) fromLoc.getY());
Vector difference = fromVec.minus(center);
Vector end = center.plus(difference.invert());
return Location.create((int)end.getX(), (int)end.getY(), fromLoc.getZ());
}
/**
* Gets the name of this node.
* @return The name.
@@ -266,4 +282,4 @@ public abstract class Node {
public void setRenderable(boolean renderable) {
this.renderable = renderable;
}
}
}
@@ -150,6 +150,7 @@ object ServerConfigParser {
ServerConstants.DRAGON_AXE_USE_OSRS_SPEC = data.getBoolean("world.dragon_axe_use_osrs_spec", false)
ServerConstants.DISCORD_OPENRSC_HOOK = data.getString("server.openrsc_integration_webhook", "")
ServerConstants.ENABLE_GLOBALCHAT = data.getBoolean("world.enable_globalchat", true)
ServerConstants.MAX_PATHFIND_DISTANCE = data.getLong("server.max_pathfind_dist", 25L).toInt()
val logLevel = data.getString("server.log_level", "VERBOSE").uppercase()
ServerConstants.LOG_LEVEL = parseEnumEntry<LogLevel>(logLevel) ?: LogLevel.VERBOSE
@@ -201,6 +201,17 @@ public final class RegionPlane {
public Scenery[][] getObjects() {
return objects;
}
public List<Scenery> getObjectList() {
ArrayList<Scenery> list = new ArrayList();
for (int x = 0; x < REGION_SIZE; x++) {
for (int y = 0; y < REGION_SIZE; y++) {
if (objects[x][y] != null)
list.add(objects[x][y]);
}
}
return list;
}
/**
* Clears this region plane.
@@ -422,4 +433,4 @@ public final class RegionPlane {
return chunks;
}
}
}
@@ -151,6 +151,10 @@ public abstract class Pathfinder {
return find(start, destination, true, SMART);
}
public static Path find(Location start, Node destination, int moverSize) {
return find(start, moverSize, destination, true, SMART, RegionManager::getClippingFlag);
}
/**
* Finds a path from the start location to the end location.
* @param destination The destination node.
@@ -4,6 +4,8 @@ import core.game.world.GameWorld
import core.game.world.map.Direction
import core.game.world.map.Location
import core.game.world.map.Point
import core.api.utils.Vector
import core.ServerConstants
import java.util.Comparator
import java.util.PriorityQueue
@@ -95,9 +97,22 @@ internal constructor() : Pathfinder() {
}
}
override fun find(start: Location?, moverSize: Int, end: Location?, sizeX: Int, sizeY: Int, rotation: Int, type: Int, walkingFlag: Int, near: Boolean, clipMaskSupplier: ClipMaskSupplier?): Path {
override fun find(start: Location?, moverSize: Int, dest: Location?, sizeX: Int, sizeY: Int, rotation: Int, type: Int, walkingFlag: Int, near: Boolean, clipMaskSupplier: ClipMaskSupplier?): Path {
reset()
assert(start != null && end != null)
assert(start != null && dest != null)
var vec = Vector.betweenLocs(start!!, dest!!)
var mag = kotlin.math.floor(vec.magnitude())
var end = dest!!
if (mag > ServerConstants.MAX_PATHFIND_DISTANCE) {
try {
if (mag < 50.0) { //truncate the path if it's realistically long
vec = vec.normalized() * (ServerConstants.MAX_PATHFIND_DISTANCE - 1)
end = start!!.transform(vec)
} else throw Exception("Pathfinding distance exceeds server max! -> " + mag.toString() + " {" + start + "->" + end + "}")
} catch (e: Exception) {
e.printStackTrace()
}
}
val path = Path()
foundPath = false
for (x in 0..103) {
@@ -226,6 +241,8 @@ internal constructor() : Pathfinder() {
path.points.add(Point(absX, absY))
}
path.setSuccesful(true)
if (end != dest)
path.isMoveNear = true
return path
}
@@ -55,6 +55,7 @@ import core.net.packet.`in`.Packet
import core.net.packet.`in`.RunScript
import core.tools.Log
import core.worker.ManagementEvents
import core.api.utils.Vector
import java.io.PrintWriter
import java.io.StringWriter
import java.lang.Math.min
@@ -452,15 +453,22 @@ object PacketProcessor {
//there's more data in this packet, we're just not using it
}
var loc = Location.create(x,y,player.location.z)
var canWalk = !player.locks.isMovementLocked
val vec = Vector.betweenLocs(player.location, loc)
if (vec.magnitude() > ServerConstants.MAX_PATHFIND_DISTANCE) {
val newVec = vec.normalized() * (ServerConstants.MAX_PATHFIND_DISTANCE - 1)
loc = player.location.transform(newVec)
}
if (canWalk && player.interfaceManager.isOpened && !player.interfaceManager.opened.definition.isWalkable)
canWalk = canWalk && player.interfaceManager.close()
if (canWalk && player.interfaceManager.hasChatbox() && !player.interfaceManager.chatbox.definition.isWalkable)
player.interfaceManager.closeChatbox()
if (!canWalk || !player.dialogueInterpreter.close()) {
player.debug("[WALK ACTION]-- NO HANDLE: PLAYER LOCKED OR INTERFACES SAY NO")
player.debug("[WALK ACTION]-- Action canceled. Either player is locked, interfaces can't close, or distance is beyond server pathfinding limit.")
return sendClearMinimap(player)
}
@@ -474,7 +482,7 @@ object PacketProcessor {
player.faceLocation(null)
player.scripts.reset()
player.pulseManager.run(object : MovementPulse(player, Location.create(x,y,player.location.z), isRunning) {
player.pulseManager.run(object : MovementPulse(player, loc, isRunning) {
override fun pulse(): Boolean {
if (isRunning)
player.walkingQueue.isRunning = false
@@ -798,4 +806,4 @@ object PacketProcessor {
}
const val BASE_CHAT_CUTOFF = 81
}
}