package o1game.Server import java.net.Socket import scala.math.min import o1game.constants.* object Client: def parseClient(data: String, socket: Socket): Client = Client(socket, Some(GameCharacter(data, Vector()))) class Client(val socket: Socket, val character: Option[GameCharacter]): private var incompleteMessage: Array[Byte] = Array.fill(MAX_MSG_SIZE)(0.toByte) private var incompleteMessageIndex = 0 /** Calculates the amount of bytes available for future incoming messages */ def spaceAvailable: Int = MAX_MSG_SIZE - incompleteMessageIndex /** Sets `data` as received for the client. * * @return false means there was not enough space to receive the message */ def receiveData(data: Vector[Byte]): Boolean = for i <- 0 until min(data.length, spaceAvailable) do this.incompleteMessage(this.incompleteMessageIndex + i) = data(i) this.incompleteMessageIndex += data.length this.incompleteMessageIndex = min(this.incompleteMessageIndex, MAX_MSG_SIZE) data.length < spaceAvailable /** Returns one line of data if there are any line breaks. * Removes the parsed data from the message buffering area. */ private def nextLine(): Option[String] = val nextLF = this.incompleteMessage.indexOf(LF) if nextLF != -1 then val message = this.incompleteMessage.take(nextLF) val rest = this.incompleteMessage.drop(nextLF + 1) this.incompleteMessage = rest ++ Array.fill(nextLF + 1)(0.toByte) // TODO: the conversion may probably be exploited to crash the server Some(String(message)) else None /** Causes the client to take the actions it has received */ def executeActions(): Unit = LazyList.continually(this.nextLine()) .takeWhile(_.isDefined) .flatten .foreach(s => println(s"`$this` executing `$s`")) class Clients(maxClients: Int): private val clients: Array[Option[Client]] = Array.fill(maxClients)(None) /** Adds `client` to this collection of clients. * * @param client the Client to add * @return true if there was room for the client * i.e. fewer clients than `maxClients`, false otherwise */ def addClient(client: Client): Boolean = val i = this.clients.indexOf(None) if i == -1 then false else this.clients(i) = Some(client) true def allClients: Iterable[Client] = clients.toVector.flatten def foreach(f: Client => Any): Unit = this.clients.flatten.foreach(f) def removeNonSatisfying(f: Client => Boolean): Unit = for i <- this.clients.indices do this.clients(i) match case Some(c) => if !f(c) then this.clients(i) = None case None =>