diff options
author | Joel Kronqvist <joel.kronqvist@iki.fi> | 2024-11-21 23:19:00 +0200 |
---|---|---|
committer | Joel Kronqvist <joel.kronqvist@iki.fi> | 2024-11-21 23:19:00 +0200 |
commit | 49985d1d11c426968fc298469671326aace96d00 (patch) | |
tree | 1d6eacf11e0791a93c216ecfeca4a5d71602f1ee | |
parent | 607b43a84d3bc8edffa05c722c7b8c3e6f72e964 (diff) | |
download | scalevalapokalypsi-49985d1d11c426968fc298469671326aace96d00.tar.gz scalevalapokalypsi-49985d1d11c426968fc298469671326aace96d00.zip |
Fixed singing from last commit
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/scalevalapokalypsi/Client/Client.scala | 1 | ||||
-rw-r--r-- | src/scalevalapokalypsi/Model/Entities/Entity.scala | 5 | ||||
-rw-r--r-- | src/scalevalapokalypsi/Model/Entities/Player.scala | 2 | ||||
-rw-r--r-- | src/scalevalapokalypsi/Server/Client.scala | 58 | ||||
-rw-r--r-- | src/scalevalapokalypsi/Server/Server.scala | 6 | ||||
-rw-r--r-- | src/scalevalapokalypsi/main.scala | 51 |
7 files changed, 75 insertions, 49 deletions
@@ -1 +1,2 @@ out +.scala-build diff --git a/src/scalevalapokalypsi/Client/Client.scala b/src/scalevalapokalypsi/Client/Client.scala index 75ce2e7..0532038 100644 --- a/src/scalevalapokalypsi/Client/Client.scala +++ b/src/scalevalapokalypsi/Client/Client.scala @@ -77,7 +77,6 @@ class Client(socket: Socket): ) private val turnInfo = RoomState() - /** Takes a client step and optionally returns an in-game event for UI * * @param clientInput one line of client input if any diff --git a/src/scalevalapokalypsi/Model/Entities/Entity.scala b/src/scalevalapokalypsi/Model/Entities/Entity.scala index e7cd45c..0427297 100644 --- a/src/scalevalapokalypsi/Model/Entities/Entity.scala +++ b/src/scalevalapokalypsi/Model/Entities/Entity.scala @@ -58,10 +58,7 @@ class Entity( ("Olet täysin kunnossa.", s"$name näyttää kuin vastasyntyneeltä.") /** Does nothing, except possibly in inherited classes. */ - def observeString(observation: String): Unit = - println(" [debug] entity got observation string & discarded it") - def observe(event: Event): Unit = - println(" [debug] entity got observation event & discarded it") + def observe(event: Event): Unit = () /** Returns the player’s current location. */ def location = this.currentLocation diff --git a/src/scalevalapokalypsi/Model/Entities/Player.scala b/src/scalevalapokalypsi/Model/Entities/Player.scala index cac5bf1..a66f521 100644 --- a/src/scalevalapokalypsi/Model/Entities/Player.scala +++ b/src/scalevalapokalypsi/Model/Entities/Player.scala @@ -18,8 +18,6 @@ class Player(name: String, initialLocation: Area) extends Entity(name, initialLo private val observedEvents: Buffer[Event] = Buffer.empty private var pendingSingEffect: Option[SingEffect] = None - override def observeString(observation: String): Unit = - this.observations.append(observation) override def observe(event: Event): Unit = this.observedEvents.append(event) diff --git a/src/scalevalapokalypsi/Server/Client.scala b/src/scalevalapokalypsi/Server/Client.scala index 17c3777..d689356 100644 --- a/src/scalevalapokalypsi/Server/Client.scala +++ b/src/scalevalapokalypsi/Server/Client.scala @@ -20,13 +20,15 @@ class Client(val socket: Socket): private var nextAction: Option[Action] = None private var turnUsed = false private var singStartTime: Option[Long] = None + private var verseToSing: String = "" def clientHasSong = this.singStartTime.isDefined - def startSong(): Unit = + def startSong(verse: String): Unit = + this.verseToSing = verse this.singStartTime = Some(currentTimeMillis() / 1000) /** Calculates the amount of bytes available for future incoming messages */ - def spaceAvailable: Int = MAX_MSG_SIZE - incompleteMessageIndex + def spaceAvailable: Int = this.incompleteMessage.size - incompleteMessageIndex - 1 /** Tests whether the client has behaved according to protocol. * @@ -75,12 +77,13 @@ class Client(val socket: Socket): * @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 + if data.length > this.spaceAvailable then + false + else + for i <- 0 until min(data.length, this.spaceAvailable) do + this.incompleteMessage(this.incompleteMessageIndex+i) = data(i) + this.incompleteMessageIndex += data.length + true /** Returns data that should be sent to this client. * The data is cleared when calling. @@ -109,6 +112,7 @@ class Client(val socket: Socket): val message = this.incompleteMessage.take(nextCRLF) val rest = this.incompleteMessage.drop(nextCRLF + 2) this.incompleteMessage = rest ++ Array.fill(nextCRLF + 1)(0.toByte) + this.incompleteMessageIndex = 0 // TODO: the conversion may probably be exploited to crash the server Some(String(message)) else @@ -158,43 +162,31 @@ class Client(val socket: Socket): /** Buffers the action for execution or executes it immediately if it * doesn't take a turn */ private def executeLine(line: String) = + if !this.turnUsed then this.singStartTime match case Some(t) => + val timePassed = currentTimeMillis()/1000 - t - this.player.foreach(_.applySingEffect( - 1 / max(5, timePassed) * 5 - )) + + val quality = if line == this.verseToSing then + 5.0 / max(5.0, timePassed.toDouble) + else + 0.0 + + this.player.foreach(_.applySingEffect(quality.toFloat)) + this.singStartTime = None + case None => + val action = Action(line) val takesATurn = this.character.exists(p => action.execute(p)) if takesATurn then this.addDataToSend(s"$ACTION_BLOCKING_INDICATOR") this.turnUsed = true - /* - val takesATurn = this.character.exists(action.execute(_)) - if takesATurn then - this.addDataToSend(s"$ACTION_BLOCKING_INDICATOR") - if ( - this.nextAction.isEmpty && - this.player.exists(action.takesATurnFor(_)) - ) then - this.nextAction = Some(action) - else if this.nextAction.isEmpty then - this.singStartTime match - case Some(t) => - val timePassed = currentTimeMillis()/1000 - t - this.player.foreach(_.applySingEffect( - 1 / max(5, timePassed) * 5 - )) - this.singStartTime = None - case None => - this.addDataToSend( - s"$ACTION_NONBLOCKING_INDICATOR${this.executeAction(action)}" - )*/ - + end executeLine end Client diff --git a/src/scalevalapokalypsi/Server/Server.scala b/src/scalevalapokalypsi/Server/Server.scala index bfb0893..8debdba 100644 --- a/src/scalevalapokalypsi/Server/Server.scala +++ b/src/scalevalapokalypsi/Server/Server.scala @@ -123,12 +123,14 @@ class Server( val target = c.player.flatMap(_.getSingEffectTarget) target.foreach(t => if c.player.exists(_.isSinging) && !c.clientHasSong then + val verse = t.getVerseAgainst + println(s"got verse against: “$verse”") this.writeToClient( - s"${SING_INDICATOR}${t.getVerseAgainst}\r\n", + s"${SING_INDICATOR}$verse\r\n", // TODO: store the verse and check how close client input is when determining sing quality c ) - c.startSong() + c.startSong(verse) ) ) diff --git a/src/scalevalapokalypsi/main.scala b/src/scalevalapokalypsi/main.scala index f953751..e357845 100644 --- a/src/scalevalapokalypsi/main.scala +++ b/src/scalevalapokalypsi/main.scala @@ -4,6 +4,7 @@ import scalevalapokalypsi.Client.{newClient, Client, StdinLineReader, GameEvent} import scalevalapokalypsi.Server.Server import scalevalapokalypsi.constants.* import java.lang.Thread.sleep +import java.lang.System.currentTimeMillis import scala.util.Try import java.lang.Thread @@ -45,16 +46,27 @@ def startClient(client: Client): Unit = val printer = Printer() while !hasQuit do sleep(POLL_INTERVAL) - val gameEvent = client.clientStep(stdinReader.newLine()) - printer.printGameEvent(gameEvent) + val line = stdinReader.newLine() + if line.map(_.length).getOrElse(0) > 1024 then + printer.printLn("Virhe: Syötteesi oli liian pitkä.") + else if line == Some("quit") then + hasQuit = true + else + val gameEvent = client.clientStep(line) + printer.printGameEvent(gameEvent) class Printer: var inputIndicatorAtStartOfLine = false + var queriedLineToSing = false + var singStartTime: Option[Long] = None + def printGameEvent(gameEvent: GameEvent): Unit = + val actions = gameEvent.actions.map(_.mkString("\n")) val roomState = gameEvent.roomState.map(_.toString) val lineToSing = gameEvent.lineToSing + if inputIndicatorAtStartOfLine && (actions.isDefined || @@ -62,17 +74,42 @@ class Printer: lineToSing.isDefined) then this.printLn("") + actions.foreach(this.printLn(_)) + roomState.foreach(this.printLn(_)) - lineToSing.foreach(this.printLn(_)) + + lineToSing match + case Some(l) => + if this.singStartTime.isEmpty then + this.singStartTime = Some(currentTimeMillis() / 1000) + print(s"Laula: “$l”\n ") + val timeSpent = this.singStartTime.map((t: Long) => + (currentTimeMillis / 1000 - t).toString + ).getOrElse("?") + print(this.timeIndicatorUpdater(timeSpent)) + case None => + this.singStartTime = None + val timeLeft = s"${gameEvent.timeToNextTurn.getOrElse("∞")}" - if gameEvent.playerCanAct && !inputIndicatorAtStartOfLine then + + if + gameEvent.playerCanAct && + lineToSing.isEmpty && + !inputIndicatorAtStartOfLine + then this.inputIndicatorAtStartOfLine = true print(s"[$timeLeft s]> ") - if gameEvent.playerCanAct then - print(s"\u001b[s\u001b[0E[$timeLeft s]\u001b[u") - private def printLn(s: String): Unit = + if gameEvent.playerCanAct && lineToSing.isEmpty then + print(this.timeIndicatorUpdater(timeLeft)) + + end printGameEvent + + def printLn(s: String): Unit = println(s) this.inputIndicatorAtStartOfLine = false + + private def timeIndicatorUpdater(t: String): String = + s"\u001b[s\u001b[0E[$t s]> \u001b[u" |