update client: implement character creation, log in 20 characters

This commit is contained in:
Jakob Gillich 2023-03-26 12:41:59 +00:00
parent bcd451e23e
commit 6584bdff9b
No known key found for this signature in database
GPG key ID: FD8BF52DB8452C91
2 changed files with 59 additions and 18 deletions

View file

@ -48,30 +48,52 @@ import scala.collection.mutable
import scala.concurrent.duration.{DurationInt, FiniteDuration} import scala.concurrent.duration.{DurationInt, FiniteDuration}
import scala.reflect.ClassTag import scala.reflect.ClassTag
import java.util.concurrent.{Executors, TimeUnit} import java.util.concurrent.{Executors, TimeUnit}
import net.psforever.packet.game.CharacterCreateRequestMessage
import net.psforever.types.CharacterSex
import net.psforever.types.PlanetSideEmpire
import net.psforever.types.CharacterVoice
import net.psforever.packet.game.ActionResultMessage
import scala.concurrent.Future
import scala.concurrent.Await
import scala.concurrent.duration.Duration
object Client { object Client {
implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global
Security.addProvider(new BouncyCastleProvider) Security.addProvider(new BouncyCastleProvider)
private[this] val log = org.log4s.getLogger private[this] val log = org.log4s.getLogger
def main(args: Array[String]): Unit = { def main(args: Array[String]): Unit = {
val client = new Client("test", "test")
client.login(new InetSocketAddress("localhost", 51000))
client.joinWorld(client.state.worlds.head)
client.selectCharacter(client.state.characters.head.charId)
client.startTasks()
while (true) { for (i <- 0 until 20) {
client.updateAvatar(client.state.avatar.copy(crouching = !client.state.avatar.crouching)) val id = i
Thread.sleep(2000)
//Thread.sleep(Int.MaxValue) new Thread {
override def run: Unit = {
val client = new Client(s"bot${id}", "bot")
client.login(new InetSocketAddress("localhost", 51000))
client.joinWorld(client.state.worlds.head)
if (client.state.characters.isEmpty) {
client.createCharacter(s"bot${id}")
}
client.selectCharacter(client.state.characters.head.charId)
client.startTasks()
while (true) {
client.updateAvatar(client.state.avatar.copy(crouching = !client.state.avatar.crouching))
Thread.sleep(2000)
}
}
}.start()
} }
Await.ready(Future.never, Duration.Inf)
} }
} }
class Client(username: String, password: String) { class Client(username: String, password: String) {
import Client._
private var sequence = 0 private var sequence = 0
private def nextSequence = { private def nextSequence = {
val r = sequence val r = sequence
@ -188,21 +210,34 @@ class Client(username: String, password: String) {
} }
setupConnection() setupConnection()
send(ConnectToWorldRequestMessage("", state.token.get, 0, 0, 0, "", 0)).require send(ConnectToWorldRequestMessage("", state.token.get, 0, 0, 0, "", 0)).require
waitFor[CharacterInfoMessage]().require while (true) {
val r = waitFor[CharacterInfoMessage]().require
if (r.finished) {
return
}
}
} }
def selectCharacter(charId: Long): Unit = { def selectCharacter(charId: Long): Unit = {
assert(state.connection == Connection.AvatarSelection) assert(state.connection == Connection.AvatarSelection)
send(CharacterRequestMessage(charId, CharacterRequestAction.Select)).require send(CharacterRequestMessage(charId, CharacterRequestAction.Select)).require
waitFor[LoadMapMessage](timeout = 15.seconds).require waitFor[LoadMapMessage](timeout = 30.seconds).require
} }
def createCharacter(): Unit = { def createCharacter(name: String): Unit = {
??? assert(state.connection == Connection.AvatarSelection)
send(CharacterCreateRequestMessage(name, 0, CharacterVoice.Voice1, CharacterSex.Male, PlanetSideEmpire.TR)).require
val r = waitFor[ActionResultMessage](timeout = 15.seconds).require
assert(r.errorCode == None)
while (true) {
val r = waitFor[CharacterInfoMessage]().require
if (r.finished) {
return
}
}
} }
def deleteCharacter(charId: Long): Unit = { def deleteCharacter(charId: Long): Unit = {
??? // never been tested
assert(state.connection == Connection.AvatarSelection) assert(state.connection == Connection.AvatarSelection)
send(CharacterRequestMessage(charId, CharacterRequestAction.Delete)).require send(CharacterRequestMessage(charId, CharacterRequestAction.Delete)).require
} }

View file

@ -89,8 +89,14 @@ case class State(
case LoginRespMessage(token, _, _, _, _, _, _) => this.copy(token = Some(token)) case LoginRespMessage(token, _, _, _, _, _, _) => this.copy(token = Some(token))
case VNLWorldStatusMessage(_, worlds) => this.copy(worlds = worlds, connection = Connection.WorldSelection) case VNLWorldStatusMessage(_, worlds) => this.copy(worlds = worlds, connection = Connection.WorldSelection)
case ObjectCreateDetailedMessage(_, objectClass, guid, _, _) => this.copy(objects = objects ++ Seq(guid.guid)) case ObjectCreateDetailedMessage(_, objectClass, guid, _, _) => this.copy(objects = objects ++ Seq(guid.guid))
case message @ CharacterInfoMessage(_, _, _, _, _, _) => case message @ CharacterInfoMessage(_, _, _, _, finished, _) =>
this.copy(characters = characters ++ Seq(message), connection = Connection.AvatarSelection) // if finished is true, it is not real character but rather signal that list is complete
if (finished) {
this.copy(connection = Connection.AvatarSelection)
} else {
this.copy(characters = characters ++ Seq(message), connection = Connection.AvatarSelection)
}
case _ => this case _ => this
}).copy(avatar = avatar.update(packet)) }).copy(avatar = avatar.update(packet))