Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run file server earlier on startup & rename forceWalk to exactMove #467

Merged
merged 5 commits into from
Mar 6, 2024
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
Expand Up @@ -5,8 +5,8 @@ import org.koin.dsl.module
import org.rsmod.game.pathfinder.LineValidator
import org.rsmod.game.pathfinder.PathFinder
import org.rsmod.game.pathfinder.StepValidator
import world.gregs.voidps.engine.client.ConnectionGatekeeper
import world.gregs.voidps.engine.client.ConnectionQueue
import world.gregs.voidps.engine.client.LoginManager
import world.gregs.voidps.engine.client.update.batch.ZoneBatchUpdates
import world.gregs.voidps.engine.data.PlayerAccounts
import world.gregs.voidps.engine.data.definition.*
Expand Down Expand Up @@ -48,7 +48,7 @@ val engineModule = module {
single {
ConnectionQueue(getIntProperty("connectionPerTickCap", 1))
}
single { ConnectionGatekeeper(get()) }
single { LoginManager(get<Players>().indexer) }
single(createdAtStart = true) { GameObjectCollision(get()) }
// Collision
single { Collisions() }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package world.gregs.voidps.engine.client

import world.gregs.voidps.network.SessionManager
import java.util.concurrent.ConcurrentHashMap

/**
* Keeps track of number of clients per ip address
*/
class ClientManager : SessionManager {
private val connections = ConcurrentHashMap<String, Int>()

override fun count(key: String) = connections[key] ?: 0

override fun add(key: String): Int? {
connections[key] = count(key) + 1
return null
}

override fun remove(key: String) {
val count = count(key) - 1
if (count <= 0) {
connections.remove(key)
} else {
connections[key] = count
}
}

override fun clear() {
connections.clear()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package world.gregs.voidps.engine.client

import world.gregs.voidps.engine.client.ui.chat.toInt
import world.gregs.voidps.engine.entity.character.IndexAllocator
import world.gregs.voidps.network.SessionManager
import java.util.concurrent.ConcurrentHashMap

/**
* Keeps track of the players online, prevents duplicate login attempts
*/
class LoginManager(
private val indices: IndexAllocator
) : SessionManager {

private val online = ConcurrentHashMap.newKeySet<String>()

override fun count(key: String) = online.contains(key).toInt()

override fun add(key: String): Int? {
if (!online.add(key)) {
return null
}
return indices.obtain()
}

override fun remove(key: String) {
online.remove(key)
}

override fun clear() {
indices.clear()
online.clear()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,14 @@ import world.gregs.voidps.engine.entity.character.move.tele
import world.gregs.voidps.engine.entity.character.npc.NPC
import world.gregs.voidps.engine.entity.character.player.Player
import world.gregs.voidps.engine.entity.character.player.appearance
import world.gregs.voidps.engine.entity.character.player.movementType
import world.gregs.voidps.engine.entity.character.player.skill.Skill
import world.gregs.voidps.engine.entity.obj.GameObject
import world.gregs.voidps.engine.entity.obj.ObjectShape
import world.gregs.voidps.engine.get
import world.gregs.voidps.engine.queue.strongQueue
import world.gregs.voidps.network.visual.VisualMask
import world.gregs.voidps.network.visual.Visuals
import world.gregs.voidps.network.visual.update.Hitsplat
import world.gregs.voidps.network.visual.update.Turn
import world.gregs.voidps.network.visual.update.player.MoveType
import world.gregs.voidps.network.visual.update.player.TemporaryMoveType
import world.gregs.voidps.type.Delta
import world.gregs.voidps.type.Direction
import world.gregs.voidps.type.Distance
Expand All @@ -34,7 +30,7 @@ fun Character.flagForceChat() = visuals.flag(if (this is Player) VisualMask.PLAY

fun Character.flagHits() = visuals.flag(if (this is Player) VisualMask.PLAYER_HITS_MASK else VisualMask.NPC_HITS_MASK)

fun Character.flagForceMovement() = visuals.flag(if (this is Player) VisualMask.PLAYER_FORCE_MOVEMENT_MASK else VisualMask.NPC_FORCE_MOVEMENT_MASK)
fun Character.flagExactMovement() = visuals.flag(if (this is Player) VisualMask.PLAYER_EXACT_MOVEMENT_MASK else VisualMask.NPC_EXACT_MOVEMENT_MASK)

fun Character.flagTurn() = visuals.flag(if (this is Player) VisualMask.PLAYER_TURN_MASK else VisualMask.NPC_TURN_MASK)

Expand Down Expand Up @@ -176,14 +172,14 @@ private fun watchIndex(character: Character) = if (character is Player) characte
* @param startDelay Client ticks until starting the movement
* @param direction The cardinal direction to face during movement
*/
fun Character.setForceMovement(
fun Character.setExactMovement(
endDelta: Delta = Delta.EMPTY,
endDelay: Int = 0,
startDelta: Delta = Delta.EMPTY,
startDelay: Int = 0,
direction: Direction = Direction.NONE
) {
val move = visuals.forceMovement
val move = visuals.exactMovement
check(endDelay > startDelay) { "End delay ($endDelay) must be after start delay ($startDelay)." }
move.startX = startDelta.x
move.startY = startDelta.y
Expand All @@ -192,19 +188,19 @@ fun Character.setForceMovement(
move.endY = endDelta.y
move.endDelay = endDelay
move.direction = direction.ordinal
flagForceMovement()
flagExactMovement()
}

fun Character.forceWalk(delta: Delta, delay: Int = tile.distanceTo(tile.add(delta)) * 30, direction: Direction = Direction.NONE) {
fun Character.exactMove(delta: Delta, delay: Int = tile.distanceTo(tile.add(delta)) * 30, direction: Direction = Direction.NONE) {
val start = tile
tele(delta)
setForceMovement(Delta.EMPTY, delay, start.delta(tile), direction = direction)
setExactMovement(Delta.EMPTY, delay, start.delta(tile), direction = direction)
}

fun Character.forceWalk(target: Tile, delay: Int = tile.distanceTo(target) * 30, direction: Direction = Direction.NONE) {
fun Character.exactMove(target: Tile, delay: Int = tile.distanceTo(target) * 30, direction: Direction = Direction.NONE) {
val start = tile
tele(target)
setForceMovement(Delta.EMPTY, delay, start.delta(tile), direction = direction)
setExactMovement(Delta.EMPTY, delay, start.delta(tile), direction = direction)
}

val Character.turn: Delta
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ suspend fun CharacterContext.pauseForever() {
}

/**
* Movement delay, typically used by interactions that perform animations or force movements
* Movement delay, typically used by interactions that perform animations or exact movements
*/
suspend fun CharacterContext.arriveDelay() {
val delay = character.remaining("last_movement")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package world.gregs.voidps.engine.client

import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

class ClientManagerTest {

private lateinit var manager: ClientManager

@BeforeEach
fun setup() {
manager = ClientManager()
}

@Test
fun `Same addresses are counted`() {
val address = "123.456.789"
assertEquals(0, manager.count(address))
manager.add(address)
assertEquals(1, manager.count(address))
manager.add(address)
assertEquals(2, manager.count(address))
manager.add(address)
assertEquals(3, manager.count(address))
}

@Test
fun `Different addresses are separate`() {
assertEquals(0, manager.count("123.456.789"))
manager.add("123.456.789")
assertEquals(0, manager.count("100.000.000"))
manager.add("100.000.000")

assertEquals(1, manager.count("100.000.000"))
assertEquals(1, manager.count("123.456.789"))
}

@Test
fun `Disconnections aren't counted`() {
val address = "123.456.789"
assertEquals(0, manager.count(address))
manager.add(address)
manager.add(address)
assertEquals(2, manager.count(address))
manager.remove(address)
assertEquals(1, manager.count(address))
}

@Test
fun `Too many disconnections isn't negative`() {
val address = "123.456.789"
assertEquals(0, manager.count(address))
manager.add(address)
assertEquals(1, manager.count(address))
manager.remove(address)
assertEquals(0, manager.count(address))
manager.remove(address)
assertEquals(0, manager.count(address))
}

@Test
fun `Clearing removes all counts`() {
val address = "123.456.789"
manager.add(address)
assertEquals(1, manager.count(address))
manager.clear()
assertEquals(0, manager.count(address))
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ internal class ConnectionQueueTest : KoinMock() {
single {
ConnectionQueue(getIntProperty("connectionPerTickCap", 1))
}
single { ConnectionGatekeeper(get()) }
}
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package world.gregs.voidps.engine.client

import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import world.gregs.voidps.engine.entity.character.IndexAllocator

class LoginManagerTest {

private lateinit var manager: LoginManager
private lateinit var indices: IndexAllocator

@BeforeEach
fun setup() {
indices = IndexAllocator(5)
manager = LoginManager(indices)
}

@Test
fun `Same names can't be added twice`() {
val name = "player"
assertEquals(0, manager.count(name))
assertEquals(1, manager.add(name))
assertEquals(1, manager.count(name))
assertNull(manager.add(name))
assertEquals(1, manager.count(name))
}

@Test
fun `Different names different count`() {
val name1 = "player1"
val name2 = "player2"
assertEquals(0, manager.count(name1))
assertEquals(1, manager.add(name1))
assertEquals(1, manager.count(name1))
assertEquals(0, manager.count(name2))
assertEquals(2, manager.add(name2))
assertEquals(1, manager.count(name2))
}

@Test
fun `Removed named clear count`() {
val name = "player"
assertEquals(1, manager.add(name))
assertEquals(1, manager.count(name))
manager.remove(name)
assertEquals(0, manager.count(name))
}

@Test
fun `Removing name twice doesn't cause negative count`() {
val name = "player"
assertEquals(1, manager.add(name))
assertEquals(1, manager.count(name))
manager.remove(name)
assertEquals(0, manager.count(name))
manager.remove(name)
assertEquals(0, manager.count(name))
}

@Test
fun `Clear names removes count`() {
val name = "player"
assertEquals(1, manager.add(name))
assertEquals(1, manager.count(name))
manager.clear()
assertEquals(0, manager.count(name))
assertEquals(1, manager.add(name))
}
}
Loading
Loading