blob: c7ff0753cc1e9faf42a335f315af43005b21dc50 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
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 =>
|