aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joel.kronqvist@iki.fi>2024-11-07 21:00:04 +0200
committerJoel Kronqvist <joel.kronqvist@iki.fi>2024-11-07 21:00:04 +0200
commit891b6f877ba848a3f78851a757734ebd1f066798 (patch)
tree849d4f9bac3b3e83f84b6319d7148f93f5a44c06
parentfdaec6534eb7ee902c75be3e4b732b6970abd859 (diff)
downloadscalevalapokalypsi-891b6f877ba848a3f78851a757734ebd1f066798.tar.gz
scalevalapokalypsi-891b6f877ba848a3f78851a757734ebd1f066798.zip
Added comments for documentation and reformatted old ones
-rw-r--r--src/main/scala/Server/Client.scala63
-rw-r--r--src/main/scala/Server/Clients.scala44
-rw-r--r--src/main/scala/Server/Server.scala19
3 files changed, 81 insertions, 45 deletions
diff --git a/src/main/scala/Server/Client.scala b/src/main/scala/Server/Client.scala
index 1e5dd00..d9bb529 100644
--- a/src/main/scala/Server/Client.scala
+++ b/src/main/scala/Server/Client.scala
@@ -17,24 +17,53 @@ class Client(val socket: Socket):
private var protocolIsIntact = true
private var name: Option[String] = None
- /** Calculates the amount of bytes available for future incoming messages
- */
+ /** Calculates the amount of bytes available for future incoming messages */
def spaceAvailable: Int = MAX_MSG_SIZE - incompleteMessageIndex
+ /** Tests whether the client has behaved according to protocol.
+ *
+ * @return false if there has been a protocol violation, true otherwise
+ */
def isIntactProtocolWise: Boolean = protocolIsIntact
+
+ /** Tests whether this client is initialized and ready to start the game
+ *
+ * @return true if the client is ready to join the game
+ */
def isReadyForGameStart: Boolean =
this.protocolState == WaitingForGameStart
+
+ /** Signals this client that it's joining the game. This is important so
+ * that this object knows to update its protocol state.
+ */
def gameStart(): Unit = this.protocolState = InGame
+
+ /** Returns the entity this client controls in the model.
+ *
+ * @return an option containing the entity
+ */
def entity: Option[Entity] = this.character
+
+ /** Tells this client object that it controls the specified entity.
+ *
+ * @param entity the entity this client is to control
+ */
def giveEntity(entity: Entity): Unit =
println(entity)
this.character = Some(entity)
+
+ /** Gets the name of this client, which should match the name of the entity
+ * that is given to this client. Not very useful if the client hasn't yet
+ * received the name or if it already has an entity.
+ *
+ * @return the name of this client
+ */
def getName: Option[String] = this.name
/** Sets `data` as received for the client.
- *
- * @return false means there was not enough space to receive the message
- */
+ *
+ * @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)
@@ -44,8 +73,8 @@ class Client(val socket: Socket):
data.length < spaceAvailable
/** Returns data that should be sent to this client.
- * The data is cleared when calling.
- */
+ * The data is cleared when calling.
+ */
def dataToThisClient(): String =
val a = this.outData
this.outData = ""
@@ -61,7 +90,7 @@ class Client(val socket: Socket):
/** Returns one line of data if there are any line breaks.
- * Removes the parsed data from the message buffering area.
+ * Removes the parsed data from the message buffering area.
*/
private def nextLine(): Option[String] =
val nextLF = this.incompleteMessage.indexOf(LF)
@@ -74,8 +103,7 @@ class Client(val socket: Socket):
else
None
- /** Causes the client to take the actions it has received
- */
+ /** Causes the client to take the actions it has received */
def interpretData(): Unit =
LazyList.continually(this.nextLine())
.takeWhile(_.isDefined)
@@ -83,11 +111,11 @@ class Client(val socket: Socket):
.foreach(s => takeAction(s))
/** Makes the client execute the action specified by `line`.
- * If there is a protocol error, the function changes
- * the variable `protocolIsIntact` to false.
- *
- * @param line the line to interpret
- */
+ * If there is a protocol error, the function changes
+ * the variable `protocolIsIntact` to false.
+ *
+ * @param line the line to interpret
+ */
private def takeAction(line: String): Unit =
this.protocolIsIntact = this.protocolState match
case WaitingForVersion =>
@@ -109,8 +137,9 @@ class Client(val socket: Socket):
this.character.flatMap(action.execute(_)) match
case Some(s) => this.addDataToSend(s)
case None => this.addDataToSend("You can't do that")
- this.character.map(_.location.fullDescription) match
- case Some(s) => this.addDataToSend(s)
+ this.character
+ .map(_.location.fullDescription)
+ .foreach(this.addDataToSend(_))
true
end Client
diff --git a/src/main/scala/Server/Clients.scala b/src/main/scala/Server/Clients.scala
index 24a245c..786a09a 100644
--- a/src/main/scala/Server/Clients.scala
+++ b/src/main/scala/Server/Clients.scala
@@ -6,11 +6,11 @@ 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
- */
+ *
+ * @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
@@ -20,9 +20,9 @@ class Clients(maxClients: Int):
true
/** Returns all the clients.
- *
- * @return an iterable of all the clients
- */
+ *
+ * @return an iterable of all the clients
+ */
def allClients: Iterable[Client] = clients.toVector.flatten
/** Applies the function `f` to all the clients for its side effects. */
@@ -36,17 +36,21 @@ class Clients(maxClients: Int):
*/
def forall(f: Client => Boolean): Boolean = this.clients.flatten.forall(f)
+ /** Gets the names of all the clients stored by this object.
+ *
+ * @return the names of the clients
+ */
def names: Vector[String] = this.clients.flatten.flatMap(_.getName).toVector
def isEmpty: Boolean = this.clients.flatten.isEmpty
/** Applies the function `f` to all the clients for its side effects
- * and removes all the clients for which `f([client])` returns false.
- * This is useful for doing IO with the client and removing clients
- * with stale sockets.
- *
- * @param f the function to apply to all the clients and filter them with
- */
+ * and removes all the clients for which `f([client])` returns false.
+ * This is useful for doing IO with the client and removing clients
+ * with stale sockets.
+ *
+ * @param f the function to apply to all the clients and filter them with
+ */
def removeNonSatisfying(f: Client => Boolean): Unit =
for i <- this.clients.indices do
this.clients(i) match
@@ -60,11 +64,11 @@ class Clients(maxClients: Int):
this.removeNonSatisfying(_.isIntactProtocolWise)
/** Applies the function f to all clients for its side effects.
- * If the function throws an exception, the client is removed.
- * Probably a more concise alternative to `removeNonSatisfying`,
- * but might catch exceptions unintentionally.
- *
- * @param f the function to apply for its side effects to each client
- */
+ * If the function throws an exception, the client is removed.
+ * Probably a more concise alternative to `removeNonSatisfying`,
+ * but might catch exceptions unintentionally.
+ *
+ * @param f the function to apply for its side effects to each client
+ */
def mapAndRemove(f: Client => Unit): Unit =
this.removeNonSatisfying(c => Try(f(c)).isSuccess)
diff --git a/src/main/scala/Server/Server.scala b/src/main/scala/Server/Server.scala
index c0a76ca..6fa284c 100644
--- a/src/main/scala/Server/Server.scala
+++ b/src/main/scala/Server/Server.scala
@@ -3,14 +3,17 @@ package o1game.Server
// TODO: TLS/SSL / import javax.net.ssl.SSLServerSocketFactory
-import java.io.IOException
import java.lang.Thread.sleep
import java.net.{ServerSocket, Socket}
import o1game.constants.*
import o1game.Model.Adventure
import o1game.Model.Entity
-import scala.collection.mutable.Map
+/** Converts this string to an array of bytes (probably for transmission).
+ *
+ * @param str the string to convert
+ * @return an array of bytes representing the string in UTF8.
+ */
def stringToByteArray(str: String): Array[Byte] =
str.toVector.map(_.toByte).toArray
@@ -50,9 +53,9 @@ class Server(port: Int, maxClients: Int, val timeLimit: Int):
/** Receives a new client and stores it in `clients`.
- *
- * @return describes if a client was added
- */
+ *
+ * @return describes if a client was added
+ */
private def receiveNewClient(): Boolean =
this.clientGetter.newClient() match
case Some(c) =>
@@ -62,9 +65,9 @@ class Server(port: Int, maxClients: Int, val timeLimit: Int):
false
/** Sends `message` to all clients
- *
- * @param message the message to send
- */
+ *
+ * @param message the message to send
+ */
private def writeToAll(message: String): Unit =
this.clients.mapAndRemove(c =>
val output = c.socket.getOutputStream