aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/Server/Server.scala
blob: c0a76cac325e2dac358f9c771d67b61863c3342f (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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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

def stringToByteArray(str: String): Array[Byte] =
	str.toVector.map(_.toByte).toArray

/** `Server` exists to initialize a server for the game
 *  and run it with its method `startServer`.
 */
class Server(port: Int, maxClients: Int, val timeLimit: Int):
	private val socket = ServerSocket(port)
	private val clientGetter = ConnectionGetter(socket)
	private val clients: Clients = Clients(maxClients)
	private val buffer: Array[Byte] = Array.ofDim(1024)
	private var bufferIndex = 0
	private var adventure: Option[Adventure] = None

	/** Starts the server. Won't terminate under normal circumstances. */
	def startServer(): Unit =
		while true do
			sleep(POLL_INTERVAL)
			this.receiveNewClient()
			this.readFromAll()
			this.writeClientDataToClients()
			this.clients.removeNonCompliant()
			this.clients.foreach(_.interpretData())
			if this.adventure.isEmpty && !this.clients.isEmpty && this.clients.forall(_.isReadyForGameStart) then
				this.adventure = Some(Adventure(this.clients.names))
				this.clients.foreach( c =>
					c.gameStart()
					val name = c.getName
					val entity: Option[Entity] = name match
						case Some(n) => this.adventure match
							case Some(a) => a.getPlayer(n)
							case None => None
						case None => None
					entity.map(c.giveEntity(_))
				)
				this.writeToAll(s"$timeLimit")


	/** Receives a new client and stores it in `clients`.
	 *
	 *  @return describes if a client was added
	 */
	private def receiveNewClient(): Boolean =
		this.clientGetter.newClient() match
			case Some(c) =>
				clients.addClient(Client(c))
				true
			case None =>
				false

	/** Sends `message` to all clients
	 *
	 *  @param message the message to send
	 */
	private def writeToAll(message: String): Unit =
		this.clients.mapAndRemove(c =>
			val output = c.socket.getOutputStream
			output.write(message.toVector.map(_.toByte).toArray)
			output.flush()
		)

	/** Sends every client's `dataToThisClient` to the client */
	private def writeClientDataToClients(): Unit =
		this.clients.mapAndRemove(c =>
			val output = c.socket.getOutputStream
			val data = c.dataToThisClient()
			output.write(data.toVector.map(_.toByte).toArray)
			output.flush()
		)

	/** Reads data sent by clients and stores it in the `Client`s of `clients` */
	private def readFromAll(): Unit =
		clients.mapAndRemove(c =>
			val input = c.socket.getInputStream
			while input.available() != 0 do
				val bytesRead = input.read(buffer)
				if bytesRead != -1 then
					c.receiveData(buffer.take(bytesRead).toVector)
		)

end Server