Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
spawns = [
{ id = "thormac_sorcerers_tower", x = 2702, y = 3405, level = 3 },
{ id = "ignatius_vulcan_sorcerers_tower", x = 2719, y = 3431, members = true },
{ id = "ignatius", x = 2719, y = 3431, members = true },
{ id = "baby_raccoon_brown", x = 2719, y = 3443, members = true },
{ id = "baby_raccoon_brown", x = 2724, y = 3440, members = true },
{ id = "baby_raccoon_red", x = 2721, y = 3449, members = true },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
id = 389
examine = "Nice hat."

[ignatius_vulcan_sorcerers_tower]
[ignatius]
id = 4946
examine = "The Master of Fire!"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ import world.gregs.voidps.type.Zone
* Groups messages by [Zone] to send to all subscribed [Player]s
* Batched messages are sent and cleared at the end of the tick
* Initial messages are stored until removed and sent on subscription
*
* From experimenting with OSRS, it seems like this isn't quite accurate.
* - Floor items are updated every change of zone.
* - Objects are updated based on a 2-zone radius from the last updated zone.
* (Like how region loading is a 4-zone radius)
* - Projectiles are sent within a 3-zone radius but not sent when entering a new zone.
* It's unclear where the other types fall.
*
* The types of batched messages would need to be split to replicate this behaviour.
*/
object ZoneBatchUpdates : Runnable {
private val batches: MutableMap<Int, MutableList<ZoneUpdate>> = Int2ObjectOpenHashMap()
Expand All @@ -41,29 +50,52 @@ object ZoneBatchUpdates : Runnable {
batches.getOrPut(zone.id) { ObjectArrayList() }.add(update)
}

/**
* Pre-encode batches of updates
*/
override fun run() {
for ((zone, updates) in batches) {
encoded[zone] = encodeBatch(updates.filter { !it.private })
}
}

/**
* Also send updates each batch zone change
*/
fun send(player: Player) {
val viewport = player.viewport!!
val from = viewport.lastBatchZone
send(player, from)
viewport.lastBatchZone = player.tile.zone
}

/**
* Send updates each zone change
*/
fun run(player: Player) {
val previousZone: Zone? = player["previous_zone"]
val previous = previousZone?.toRectangle(radius = player.viewport!!.localRadius)?.toZones(previousZone.level)?.toSet()
player["previous_zone"] = player.tile.zone
for (zone in player.tile.zone.toRectangle(radius = player.viewport!!.localRadius).toZonesReversed(player.tile.level)) {
val entered = previous == null || !previous.contains(zone)
if (entered) {
send(player, player.steps.previous.zone)
}

/**
* Send differences between current and previous zones
*/
private fun send(player: Player, from: Zone) {
val viewport = player.viewport ?: return
val to = player.tile.zone
val previous = from.toRectangle(radius = viewport.localRadius).toZones(from.level).toSet()
for (zone in to.toRectangle(radius = viewport.localRadius).toZonesReversed(player.tile.level)) {
val entered = !previous.contains(zone)
if (entered) { // Clear and resend raw data for newly entered areas
player.clearZone(zone)
for (sender in senders) {
sender.send(player, zone)
}
}
val updates = batches[zone.id]?.filter { it.private && it.visible(player.name) } ?: continue
if (!entered) {
if (!entered) { // Send batched updates for current regions
player.sendBatch(zone)
}
for (update in updates) {
for (update in updates) { // Send private updates separately
player.client?.send(update)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Viewport {
val npcUpdates = ArrayWriter(4000)

var lastLoadZone: Zone = Zone.EMPTY
var lastBatchZone: Zone = Zone.EMPTY
var loaded: Boolean = false
var dynamic: Boolean = false
var size: Int = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class DynamicZones(
private val refresh = IntOpenHashSet()

// All recent region changes (including clearing)
private val updated = IntOpenHashSet()
private var update = false

fun dynamic(region: Region) = regions.contains(region.id)

Expand All @@ -43,7 +43,7 @@ class DynamicZones(
regions.add(region.id)
refresh.add(region.id)
}
updated.add(to.region.id)
update = true
}

/**
Expand All @@ -70,7 +70,7 @@ class DynamicZones(
regions.remove(region.id)
}
}
updated.add(zone.region.id)
update = true
}

/**
Expand All @@ -86,21 +86,19 @@ class DynamicZones(
}
}
if (regions.remove(region.id)) {
updated.add(region.id)
update = true
}
}

/**
* Send updated regions to clients
*/
override fun run() {
if (updated.isEmpty()) {
if (!update) {
return
}
for (region in updated.iterator()) {
reloadCallback.invoke()
}
updated.clear()
reloadCallback.invoke()
update = false
refresh.clear()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,17 @@ internal class ZoneBatchUpdatesTest : KoinMock() {
// Given
val zone = Zone(2, 2)
ZoneBatchUpdates.add(zone, update)
player.viewport!!.lastBatchZone = Zone(10, 10)
player.tile = Tile(20, 20)
GameObjects.set(id = 1234, x = 21, y = 20, level = 0, shape = ObjectShape.WALL_DECOR_STRAIGHT_NO_OFFSET, rotation = 0, definition = ObjectDefinition.EMPTY)
ZoneBatchUpdates.register(GameObjects)
val added = GameObject(4321, Tile(20, 21), ObjectShape.CENTRE_PIECE_STRAIGHT, 0)
GameObjects.add(added, collision = false) // Avoid koin
GameObjects.add(added, collision = false)
val removed = GameObject(1234, Tile(21, 20), ObjectShape.WALL_DECOR_STRAIGHT_NO_OFFSET, 0)
GameObjects.remove(removed, collision = false)
player["logged_in"] = true
// When
ZoneBatchUpdates.run(player)
ZoneBatchUpdates.send(player)
// Then
verify(exactly = 1) {
client.clearZone(2, 2, 0)
Expand All @@ -77,14 +78,14 @@ internal class ZoneBatchUpdatesTest : KoinMock() {
// Given
val zone = Zone(11, 11, 1)
val lastZone = Zone(10, 10)
player["previous_zone"] = zone
player.viewport!!.lastBatchZone = zone
player.tile = zone.tile
player.viewport!!.lastLoadZone = lastZone
// Given
ZoneBatchUpdates.add(zone, update)
ZoneBatchUpdates.run()
// When
ZoneBatchUpdates.run(player)
ZoneBatchUpdates.send(player)
// Then
verify {
client.sendBatch(any<ByteArray>(), 7, 7, 1)
Expand All @@ -97,13 +98,13 @@ internal class ZoneBatchUpdatesTest : KoinMock() {
val zone = Zone(11, 11, 1)
val lastZone = Zone(10, 10, 1)
player.tile = zone.tile
player["previous_zone"] = lastZone
player.viewport!!.lastBatchZone = lastZone
every { update.private } returns true
every { update.visible(player.name) } returns true
// Given
ZoneBatchUpdates.add(zone, update)
// When
ZoneBatchUpdates.run(player)
ZoneBatchUpdates.send(player)
// Then
verify {
client.send(update)
Expand All @@ -119,13 +120,13 @@ internal class ZoneBatchUpdatesTest : KoinMock() {
val zone = Zone(11, 11, 1)
val lastZone = Zone(10, 10, 1)
player.tile = zone.tile
player["previous_zone"] = lastZone
player.viewport!!.lastBatchZone = lastZone
every { update.private } returns true
every { update.visible(player.name) } returns false
// Given
ZoneBatchUpdates.add(zone, update)
// When
ZoneBatchUpdates.run(player)
ZoneBatchUpdates.send(player)
// Then
verify(exactly = 0) {
client.send(update)
Expand Down
60 changes: 0 additions & 60 deletions game/src/main/kotlin/content/area/kandarin/catherby/Ellena.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import world.gregs.voidps.engine.entity.character.player.skill.level.Level
class Ignatius : Script {

init {
npcOperate("Trade", "armour_salesman") {
npcOperate("Trade", "ignatius") {
openShop(
"ignatiuss_hot_deals${
when {
Expand Down
26 changes: 18 additions & 8 deletions game/src/main/kotlin/content/entity/world/RegionLoading.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package content.entity.world

import world.gregs.voidps.engine.Script
import world.gregs.voidps.engine.client.instruction.instruction
import world.gregs.voidps.engine.client.update.batch.ZoneBatchUpdates
import world.gregs.voidps.engine.client.update.view.Viewport
import world.gregs.voidps.engine.data.AccountManager
import world.gregs.voidps.engine.entity.MAX_PLAYERS
Expand Down Expand Up @@ -76,18 +77,26 @@ class RegionLoading(val dynamicZones: DynamicZones) : Script {
}

fun checkReload(player: Player, to: Tile) {
if (player.networked && needsRegionChange(player)) {
if (!player.networked) {
return
}
val viewport = player.viewport!!
if (needsRegionChange(player)) {
// default radius = 4
updateRegion(player, false, crossedDynamicBoarder(player))
}
if (viewport.lastBatchZone.level != player.tile.level || !inViewOfZone(player, viewport.lastBatchZone, viewport.localRadius - 1)) {
// default radius = 2
ZoneBatchUpdates.send(player)
}
}

fun needsRegionChange(player: Player) = !inViewOfZone(player, player.viewport!!.lastLoadZone) || crossedDynamicBoarder(player)
fun needsRegionChange(player: Player) = !inViewOfZone(player, player.viewport!!.lastLoadZone, player.viewport!!.zoneRadius - 2) || crossedDynamicBoarder(player)

fun inViewOfZone(player: Player, zone: Zone): Boolean {
val viewport = player.viewport!!
val radius: Int = viewport.zoneRadius - 2
return Distance.within(player.tile.zone.x, player.tile.zone.y, zone.x, zone.y, radius)
}
/**
* Check if we're within 4 (default) zones of the last loaded zone.
*/
fun inViewOfZone(player: Player, zone: Zone, radius: Int): Boolean = Distance.within(player.tile.zone.x, player.tile.zone.y, zone.x, zone.y, radius)

fun inViewOfRegion(player: Player, region: Region): Boolean {
val viewport = player.viewport!!
Expand Down Expand Up @@ -115,6 +124,7 @@ class RegionLoading(val dynamicZones: DynamicZones) : Script {
viewport.loaded = false
}
viewport.lastLoadZone = player.tile.zone
ZoneBatchUpdates.send(player)
}

fun update(player: Player, initial: Boolean, force: Boolean) {
Expand Down Expand Up @@ -170,7 +180,7 @@ class RegionLoading(val dynamicZones: DynamicZones) : Script {
append++
}
}
for (i in 0 until append) {
for (i in 0..append) {
xteaList.add(blankXtea)
}
viewport.dynamic = true
Expand Down
Loading