diff options
Diffstat (limited to 'src/scalevalapokalypsi/Client')
-rw-r--r-- | src/scalevalapokalypsi/Client/Client.scala | 85 | ||||
-rw-r--r-- | src/scalevalapokalypsi/Client/GameEvent.scala | 11 | ||||
-rw-r--r-- | src/scalevalapokalypsi/Client/Turn.scala | 4 |
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 |