aboutsummaryrefslogtreecommitdiff
path: root/src/scalevalapokalypsi/Client
diff options
context:
space:
mode:
Diffstat (limited to 'src/scalevalapokalypsi/Client')
-rw-r--r--src/scalevalapokalypsi/Client/Client.scala85
-rw-r--r--src/scalevalapokalypsi/Client/GameEvent.scala11
-rw-r--r--src/scalevalapokalypsi/Client/Turn.scala4
3 files changed, 55 insertions, 45 deletions
diff --git a/src/scalevalapokalypsi/Client/Client.scala b/src/scalevalapokalypsi/Client/Client.scala
index aab6bc3..75ce2e7 100644
--- a/src/scalevalapokalypsi/Client/Client.scala
+++ b/src/scalevalapokalypsi/Client/Client.scala
@@ -1,12 +1,11 @@
package scalevalapokalypsi.Client
-import java.lang.Thread.sleep
-import java.net.Socket
+import java.net.{Socket,InetSocketAddress}
import scala.io.Source
import scala.sys.process.stdout
import scalevalapokalypsi.constants.*
import scalevalapokalypsi.utils.{stringToByteArray,getNCharsFromSocket}
-import scalevalapokalypsi.Client.{ReceivedLineParser,StdinLineReader,Turn}
+import scalevalapokalypsi.Client.{ReceivedLineParser,StdinLineReader,RoomState}
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
@@ -34,7 +33,8 @@ enum ServerLineState:
* @return the client created, if all was successful
*/
def newClient(name: String, ip: String, port: Int): Option[Client] =
- val socket = Socket(ip, port)
+ val socket = Socket()
+ socket.connect(new InetSocketAddress(ip, port), INITIAL_CONN_TIMEOUT)
val output = socket.getOutputStream
val input = socket.getInputStream
val initMsg = s"$GAME_VERSION\r\n$name\r\n"
@@ -61,7 +61,6 @@ class Client(socket: Socket):
private val buffer: Array[Byte] = Array.ofDim(MAX_MSG_SIZE)
private var bufferIndex = 0
private val serverLineParser = ReceivedLineParser()
- private val stdinReader = StdinLineReader()
private var serverLineState = ServerLineState.WaitingForTimeLimit
@@ -70,41 +69,50 @@ class Client(socket: Socket):
private var timeLimit: Long = 0
private var lastTurnStart: Long = 0
private var lastExecutedTurn: Long = 0
- private var isSinging: Boolean = false
+ private var lineToSing: Option[String] = None
private val bufferedActions: Buffer[String] = Buffer.empty
assert(
lastTurnStart <= lastExecutedTurn,
"don't initialize with unexecuted turn"
)
- private val turnInfo = Turn()
+ private val turnInfo = RoomState()
- /** Starts the client. This shouldn't terminate. */
- def startClient(): Unit =
-
- stdinReader.startReading()
-
- while true do
-
- sleep(POLL_INTERVAL)
+ /** Takes a client step and optionally returns an in-game event for UI
+ *
+ * @param clientInput one line of client input if any
+ * @return an event describing new changes in the game state
+ */
+ def clientStep(clientInput: Option[String]): GameEvent =
this.readAndParseDataFromServer()
- this.displayActions()
+ val actions = this.getNewActions()
- if
+ val roomState = if
this.lastExecutedTurn < this.lastTurnStart &&
- !this.isSinging
+ this.lineToSing.isEmpty
then
- print(this.giveTurn())
-
- // TODO: we probably want to quit at EOF
- stdinReader.newLine().foreach((s: String) =>
- this.isSinging = false
- output.write(stringToByteArray(s+"\r\n"))
+ this.giveTurn()
+ Some(this.turnInfo)
+ else
+ None
+
+ for line <- clientInput do
+ this.lineToSing = None
+ output.write(stringToByteArray(s"$line\r\n"))
+
+ val timeOfTurnEnd = this.lastTurnStart + this.timeLimit
+ val timeToTurnEnd = -currentTimeMillis()/1000 + timeOfTurnEnd
+ GameEvent(
+ actions,
+ roomState,
+ this.lineToSing,
+ this.canAct,
+ Some(timeToTurnEnd).filter(p => this.lastTurnStart != 0)
)
- end startClient
+ end clientStep
private def readAndParseDataFromServer(): Unit =
@@ -116,33 +124,24 @@ class Client(socket: Socket):
parseDataFromServer(buffer.take(bytesRead))
availableBytes = input.available()
- private def giveTurn(): String =
+ private def giveTurn(): Unit =
this.canAct = true
this.lastExecutedTurn = currentTimeMillis / 1000
- s"\n\n${this.turnInfo}\n${this.actionGetterIndicator}"
private def bufferAction(action: String): Unit =
this.bufferedActions += action
- private def displayActions(): Unit =
+ private def getNewActions(): Option[Vector[String]] =
val somethingToShow = this.bufferedActions.nonEmpty
- if somethingToShow then
- if !this.isSinging then
- this.bufferedActions.foreach(println(_))
- this.bufferedActions.clear()
- if !this.isSinging && this.canAct && somethingToShow then
- print(this.actionGetterIndicator)
+ if somethingToShow && this.lineToSing.isEmpty then
+ val res = this.bufferedActions.toVector
+ this.bufferedActions.clear()
+ Some(res)
+ else
+ None
private def startSong(verse: String): Unit =
- this.isSinging = true
- print(s"\nLaula: “$verse”\n> ")
-
- // TODO: this is sometimes in front of actions, use an indicator to test if newline before actions?
- private def actionGetterIndicator =
- val timeOfTurnEnd = this.lastTurnStart + this.timeLimit
- val timeToTurnEnd = -currentTimeMillis()/1000 + timeOfTurnEnd
- s"[$timeToTurnEnd]> "
-
+ this.lineToSing = Some(verse)
private def parseDataFromServer(data: Array[Byte]): Unit =
diff --git a/src/scalevalapokalypsi/Client/GameEvent.scala b/src/scalevalapokalypsi/Client/GameEvent.scala
new file mode 100644
index 0000000..8aa1e1c
--- /dev/null
+++ b/src/scalevalapokalypsi/Client/GameEvent.scala
@@ -0,0 +1,11 @@
+package scalevalapokalypsi.Client
+
+class GameEvent(
+ val actions: Option[Vector[String]],
+ val roomState: Option[RoomState],
+ val lineToSing: Option[String],
+ val playerCanAct: Boolean,
+ val timeToNextTurn: Option[Long]
+)
+
+
diff --git a/src/scalevalapokalypsi/Client/Turn.scala b/src/scalevalapokalypsi/Client/Turn.scala
index 30101c5..02fe11b 100644
--- a/src/scalevalapokalypsi/Client/Turn.scala
+++ b/src/scalevalapokalypsi/Client/Turn.scala
@@ -4,7 +4,7 @@ package scalevalapokalypsi.Client
* This class exists essentially so that the client has somewhere
* to store data about turns and something to format that data with.
*/
-class Turn:
+class RoomState:
/** Description of the area the player controlled by the client is in
* at the end of the turn. */
@@ -29,4 +29,4 @@ class Turn:
(s"$areaDescription\n$directionDesc\n" +
s"\n$itemDesc\n$entityDesc")
-end Turn
+end RoomState