Skip to content

Commit 68dcf6c

Browse files
authored
Dynamic zone fixes (#767)
* Fix region reloading for dynamic regions, hopefully solves #326 * Fix dynamic region copying objects incorrectly + add more tests
1 parent c5f18dd commit 68dcf6c

File tree

13 files changed

+306
-163
lines changed

13 files changed

+306
-163
lines changed

engine/src/main/kotlin/world/gregs/voidps/engine/entity/character/mode/move/Movement.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import world.gregs.voidps.engine.entity.character.player.temporaryMoveType
2020
import world.gregs.voidps.engine.get
2121
import world.gregs.voidps.engine.map.Overlap
2222
import world.gregs.voidps.engine.map.collision.Collisions
23-
import world.gregs.voidps.engine.map.region.RegionRetry
2423
import world.gregs.voidps.network.login.protocol.visual.update.player.MoveType
2524
import world.gregs.voidps.type.Delta
2625
import world.gregs.voidps.type.Direction
@@ -54,10 +53,6 @@ open class Movement(
5453

5554
override fun tick() {
5655
if (character is Player && character.viewport?.loaded == false) {
57-
if (character.viewport != null && character.inc("fail_load_count") > 10) {
58-
character.emit(RegionRetry)
59-
character.clear("fail_load_count")
60-
}
6156
return
6257
}
6358
if (hasDelay() && !canMove() && !character.steps.destination.noCollision) {

engine/src/main/kotlin/world/gregs/voidps/engine/map/collision/CollisionDecoder.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class CollisionDecoder(private val collisions: Collisions) {
6767
}
6868
val rotX = rotateX(localX, localY, zoneRotation)
6969
val rotY = rotateY(localX, localY, zoneRotation)
70+
7071
if (isTile(settings, localX, localY, level, ROOF_TILE)) {
7172
collisions.setUnsafe(targetX + rotX, targetY + rotY, height, CollisionFlag.ROOF)
7273
}

engine/src/main/kotlin/world/gregs/voidps/engine/map/obj/MapObjectsRotatedDecoder.kt

Lines changed: 46 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class MapObjectsRotatedDecoder(
2323
val objectData = cache.data(Index.MAPS, "l${from.region.x}_${from.region.y}", xtea = keys) ?: return
2424
val x = from.tile.x.rem(64)
2525
val y = from.tile.y.rem(64)
26-
zone = Rectangle(x, y, x + 8, y + 8)
26+
zone = Rectangle(x, y, x + 7, y + 7)
2727
zoneRotation = rotation
2828
super.decode(objectData, settings, to.tile.x, to.tile.y)
2929
}
@@ -39,55 +39,53 @@ class MapObjectsRotatedDecoder(
3939
objects.set(objectId, regionTileX + rotX, regionTileY + rotY, level, shape, objRotation, def)
4040
}
4141

42-
companion object {
43-
private fun rotateX(
44-
objX: Int,
45-
objY: Int,
46-
sizeX: Int,
47-
sizeY: Int,
48-
objRotation: Int,
49-
zoneRotation: Int,
50-
): Int {
51-
var x = sizeX
52-
var y = sizeY
53-
val rotation = zoneRotation and 0x3
54-
if (objRotation and 0x1 == 1) {
55-
val temp = x
56-
x = y
57-
y = temp
58-
}
59-
if (rotation == 0) {
60-
return objX
61-
}
62-
if (rotation == 1) {
63-
return objY
64-
}
65-
return if (rotation == 2) 7 - objX - x + 1 else 7 - objY - y + 1
42+
internal fun rotateX(
43+
objX: Int,
44+
objY: Int,
45+
sizeX: Int,
46+
sizeY: Int,
47+
objRotation: Int,
48+
zoneRotation: Int,
49+
): Int {
50+
var x = sizeX
51+
var y = sizeY
52+
val rotation = zoneRotation and 0x3
53+
if (objRotation and 0x1 == 1) {
54+
val temp = x
55+
x = y
56+
y = temp
6657
}
58+
if (rotation == 0) {
59+
return objX
60+
}
61+
if (rotation == 1) {
62+
return objY
63+
}
64+
return if (rotation == 2) 7 - objX - x + 1 else 7 - objY - y + 1
65+
}
6766

68-
private fun rotateY(
69-
objX: Int,
70-
objY: Int,
71-
sizeX: Int,
72-
sizeY: Int,
73-
objRotation: Int,
74-
zoneRotation: Int,
75-
): Int {
76-
val rotation = zoneRotation and 0x3
77-
var x = sizeY
78-
var y = sizeX
79-
if (objRotation and 0x1 == 1) {
80-
val temp = y
81-
y = x
82-
x = temp
83-
}
84-
if (rotation == 0) {
85-
return objY
86-
}
87-
if (rotation == 1) {
88-
return 7 - objX - y + 1
89-
}
90-
return if (rotation == 2) 7 - objY - x + 1 else objX
67+
internal fun rotateY(
68+
objX: Int,
69+
objY: Int,
70+
sizeX: Int,
71+
sizeY: Int,
72+
objRotation: Int,
73+
zoneRotation: Int,
74+
): Int {
75+
val rotation = zoneRotation and 0x3
76+
var x = sizeY
77+
var y = sizeX
78+
if (objRotation and 0x1 == 1) {
79+
val temp = y
80+
y = x
81+
x = temp
82+
}
83+
if (rotation == 0) {
84+
return objY
85+
}
86+
if (rotation == 1) {
87+
return 7 - objX - y + 1
9188
}
89+
return if (rotation == 2) 7 - objY - x + 1 else objX
9290
}
9391
}

engine/src/main/kotlin/world/gregs/voidps/engine/map/region/RegionRetry.kt

Lines changed: 0 additions & 16 deletions
This file was deleted.

engine/src/main/kotlin/world/gregs/voidps/engine/map/zone/DynamicZones.kt

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,37 @@ class DynamicZones(
1616
private val objects: GameObjects,
1717
private val collisions: Collisions,
1818
private val extract: MapDefinitions,
19-
) {
19+
) : Runnable {
2020
private val zones: MutableMap<Int, Int> = Int2IntArrayMap()
21+
// All dynamic regions
2122
private val regions = IntOpenHashSet()
2223

23-
fun isDynamic(region: Region) = regions.contains(region.id)
24+
// Dynamic regions that have recently been modified (not cleared)
25+
private val refresh = IntOpenHashSet()
2426

25-
fun getDynamicZone(zone: Zone) = zones[zone.id]
27+
// All recent region changes (including clearing)
28+
private val updated = IntOpenHashSet()
29+
30+
fun dynamic(region: Region) = regions.contains(region.id)
31+
32+
fun dynamicUpdate(region: Region) = refresh.contains(region.id)
33+
34+
fun dynamicZone(zone: Zone) = zones[zone.id]
2635

2736
/**
2837
* @param from The zone to be copied
2938
* @param to The zone things will be copied to
3039
*/
3140
fun copy(from: Zone, to: Zone = from, rotation: Int = 0) {
3241
zones[to.id] = from.rotatedId(rotation)
33-
update(from, to, rotation, true)
42+
objects.reset(to)
43+
collisions.clear(to)
44+
extract.loadZone(from, to, rotation)
45+
for (region in to.toCuboid(radius = 3).toRegions()) {
46+
regions.add(region.id)
47+
refresh.add(region.id)
48+
}
49+
updated.add(to.region.id)
3450
}
3551

3652
/**
@@ -49,35 +65,46 @@ class DynamicZones(
4965
*/
5066
fun clear(zone: Zone) {
5167
zones.remove(zone.id)
52-
update(zone, zone, 0, false)
68+
objects.reset(zone)
69+
collisions.clear(zone)
70+
extract.loadZone(zone, zone, 0)
71+
for (region in zone.toCuboid(radius = 3).toRegions()) {
72+
if (region.toRectangle().toZones().none { zones.containsKey(it.id) }) {
73+
regions.remove(region.id)
74+
}
75+
}
76+
updated.add(zone.region.id)
5377
}
5478

5579
/**
5680
* Clear the dynamic [region] and replace it with the original
5781
*/
5882
fun clear(region: Region) {
5983
for (zone in region.toCuboid().toZones()) {
60-
objects.clear(zone)
61-
collisions.clear(zone)
62-
extract.loadZone(zone, zone, 0)
63-
zones.remove(zone.id)
84+
if (zones.containsKey(zone.id)) {
85+
objects.clear(zone)
86+
collisions.clear(zone)
87+
extract.loadZone(zone, zone, 0)
88+
zones.remove(zone.id)
89+
}
90+
}
91+
if (regions.remove(region.id)) {
92+
updated.add(region.id)
6493
}
65-
regions.remove(region.id)
66-
World.emit(ClearRegion(region))
6794
}
6895

69-
private fun update(from: Zone, to: Zone, rotation: Int, set: Boolean) {
70-
objects.reset(to)
71-
collisions.clear(to)
72-
extract.loadZone(from, to, rotation)
73-
for (region in to.toCuboid(radius = 3).toRegions()) {
74-
if (set) {
75-
regions.add(region.id)
76-
} else if (region.toRectangle().toZones().none { zones.containsKey(it.id) }) {
77-
regions.remove(region.id)
78-
}
96+
/**
97+
* Send updated regions to clients
98+
*/
99+
override fun run() {
100+
if (updated.isEmpty()) {
101+
return
102+
}
103+
for (region in updated.iterator()) {
104+
World.emit(RegionReload(Region(region)))
79105
}
80-
World.emit(ReloadZone(to))
106+
updated.clear()
107+
refresh.clear()
81108
}
82109

83110
companion object {

engine/src/main/kotlin/world/gregs/voidps/engine/map/zone/RegionLoad.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package world.gregs.voidps.engine.map.zone
33
import world.gregs.voidps.engine.event.Event
44
import world.gregs.voidps.engine.event.EventDispatcher
55

6+
/**
7+
* Send region load to a player
8+
*/
69
object RegionLoad : Event {
710
override val size = 1
811

engine/src/main/kotlin/world/gregs/voidps/engine/map/zone/ClearRegion.kt renamed to engine/src/main/kotlin/world/gregs/voidps/engine/map/zone/RegionReload.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import world.gregs.voidps.engine.event.Event
44
import world.gregs.voidps.engine.event.EventDispatcher
55
import world.gregs.voidps.type.Region
66

7-
data class ClearRegion(val region: Region) : Event {
7+
/**
8+
* A region has been changed and needs updating for all players
9+
*/
10+
data class RegionReload(val region: Region) : Event {
811
override val size = 1
912

10-
override fun parameter(dispatcher: EventDispatcher, index: Int) = if (index == 0) "clear_region" else null
13+
override fun parameter(dispatcher: EventDispatcher, index: Int) = if (index == 0) "region_reload" else null
1114
}

engine/src/main/kotlin/world/gregs/voidps/engine/map/zone/ReloadZone.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)