aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joel.kronqvist@iki.fi>2024-11-21 23:19:00 +0200
committerJoel Kronqvist <joel.kronqvist@iki.fi>2024-11-21 23:19:00 +0200
commit49985d1d11c426968fc298469671326aace96d00 (patch)
tree1d6eacf11e0791a93c216ecfeca4a5d71602f1ee
parent607b43a84d3bc8edffa05c722c7b8c3e6f72e964 (diff)
downloadscalevalapokalypsi-49985d1d11c426968fc298469671326aace96d00.tar.gz
scalevalapokalypsi-49985d1d11c426968fc298469671326aace96d00.zip
Fixed singing from last commit
-rw-r--r--.gitignore1
-rw-r--r--src/scalevalapokalypsi/Client/Client.scala1
-rw-r--r--src/scalevalapokalypsi/Model/Entities/Entity.scala5
-rw-r--r--src/scalevalapokalypsi/Model/Entities/Player.scala2
-rw-r--r--src/scalevalapokalypsi/Server/Client.scala58
-rw-r--r--src/scalevalapokalypsi/Server/Server.scala6
-rw-r--r--src/scalevalapokalypsi/main.scala51
7 files changed, 75 insertions, 49 deletions
diff --git a/.gitignore b/.gitignore
index 1fcb152..296d678 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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"