270 lines
8.8 KiB
Scala
270 lines
8.8 KiB
Scala
package actors
|
|
|
|
import actors.UserActor.{BanMapMessage, GetName, HostLeaveLobby, LobbyFatal, Message, RefreshLobbyInfo, SecondPlayerLeaveLobby, SendBanMapMessage, SendMessage, SetUserAsHost, SetUserAsObs, SetUserAsSecondPlayer}
|
|
import akka.actor.{Actor, ActorLogging, ActorRef}
|
|
import akka.event.LoggingReceive
|
|
import com.typesafe.scalalogging.LazyLogging
|
|
import akka.pattern.ask
|
|
import akka.util.Timeout
|
|
import com.typesafe.config.{Config, ConfigFactory}
|
|
|
|
import scala.collection.JavaConverters.iterableAsScalaIterableConverter
|
|
import scala.collection.immutable.{HashSet, Queue}
|
|
import scala.concurrent.Await
|
|
import scala.concurrent.duration._
|
|
|
|
case class LobbyUser(name: String, actorRef: ActorRef)
|
|
case class DeciderMap(map: String, var isBanned: Boolean = false)
|
|
|
|
/**
|
|
* There is one StockActor per stock symbol. The StockActor maintains a list of users watching the stock and the stock
|
|
* values. Each StockActor updates a rolling dataset of randomly generated stock values.
|
|
*/
|
|
class LobbieActor(hostUser: LobbyUser) extends Actor with LazyLogging {
|
|
|
|
val config = ConfigFactory.load()
|
|
logger.info(s"Create lobby... host: ${hostUser.actorRef.path.name}")
|
|
|
|
|
|
private val host: LobbyUser = hostUser
|
|
private var secondPlayer: Option[LobbyUser] = None
|
|
|
|
private var firstPlayerReady: Boolean = false
|
|
private var secondPlayerReady: Boolean = false
|
|
|
|
private var playerTurn = 1
|
|
|
|
// all lobby users actors (observer and players)
|
|
protected[this] var users: HashSet[ActorRef] = HashSet.empty[ActorRef]
|
|
|
|
users = users + host.actorRef
|
|
|
|
private var status: LobbyStatus = NotStarted()
|
|
|
|
private var lobbyType: LobbyType = Last3()
|
|
|
|
private var isNecrons: Boolean = false
|
|
|
|
private val mapsLobby: Set[DeciderMap] = {
|
|
val configMaps = config.getStringList("maps").asScala
|
|
configMaps.map(e => {
|
|
DeciderMap(e)
|
|
}).toSet
|
|
}
|
|
|
|
hostUser.actorRef.tell(
|
|
SetUserAsHost(LobbyInfo(
|
|
UserInfo(hostUser.name,firstPlayerReady),
|
|
UserInfo("", secondPlayerReady),
|
|
self.path.name,
|
|
status.toString(),
|
|
playerTurn,
|
|
lobbyType.toString(),
|
|
isNecrons,
|
|
mapsLobby)),
|
|
this.self)
|
|
|
|
implicit val timeout: Timeout = 1.second
|
|
|
|
|
|
def receive = LoggingReceive {
|
|
case BanMap(mapName: String) =>
|
|
// notify watchers
|
|
logger.info(s"Ban map $mapName by ${sender.path.name}")
|
|
|
|
if(status == Draft()){
|
|
if((playerTurn == 1 && sender == host.actorRef) ||
|
|
(playerTurn == 2 && secondPlayer.exists(_.actorRef == sender))){
|
|
mapsLobby.find(p => p.map == mapName) match {
|
|
case Some(map) =>
|
|
if(!map.isBanned){
|
|
map.isBanned = true
|
|
if (playerTurn== 1) playerTurn = 2 else playerTurn = 1
|
|
if(mapsLobby.count(_.isBanned == false) == 3 && lobbyType == Last3() ||
|
|
mapsLobby.count(_.isBanned == false) == 5 && lobbyType == Last5() ||
|
|
mapsLobby.count(_.isBanned == false) == 9 && lobbyType == Superfinal() ||
|
|
mapsLobby.count(_.isBanned == false) == 1 && lobbyType == LooserPick()){
|
|
status = Finish()
|
|
}
|
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
|
|
|
val senderName: String = if (sender == host.actorRef) {
|
|
host.name
|
|
} else secondPlayer.get.name
|
|
users.foreach(_ ! SendBanMapMessage(BanMapMessage(senderName, mapName)))
|
|
} else {
|
|
logger.warn(s"User ban map $mapName, but map already banned")
|
|
}
|
|
case None =>
|
|
logger.error(s"Map $mapName not exist")
|
|
}
|
|
} else{
|
|
logger.warn(s"Player ${sender.path.name} ban map, but turn is $playerTurn")
|
|
}
|
|
} else {
|
|
logger.warn(s"Player ${sender.path.name} ban map, but lobby status is '$status' status")
|
|
}
|
|
case SetReady =>
|
|
// notify watchers
|
|
var readyPlayer = sender()
|
|
if(readyPlayer == hostUser.actorRef){
|
|
firstPlayerReady = true
|
|
} else if (secondPlayer.exists(sp => sp.actorRef == readyPlayer)) {
|
|
secondPlayerReady = true
|
|
}
|
|
|
|
if(firstPlayerReady && secondPlayerReady){
|
|
status = Draft()
|
|
}
|
|
|
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
|
|
|
case SetNotReady =>
|
|
// notify watchers
|
|
var notReadyPlayer = sender()
|
|
if(notReadyPlayer == hostUser.actorRef){
|
|
firstPlayerReady = false
|
|
} else if (secondPlayer.exists(sp => sp.actorRef == notReadyPlayer)) {
|
|
secondPlayerReady = false
|
|
}
|
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
|
|
|
case ChangeLobbyType(lobbyTypeNew) =>
|
|
lobbyTypeNew match {
|
|
case "last3" =>
|
|
lobbyType = Last3()
|
|
case "last5" =>
|
|
lobbyType = Last5()
|
|
case "superfinal" =>
|
|
lobbyType = Superfinal()
|
|
case "looserpick" =>
|
|
lobbyType = LooserPick()
|
|
}
|
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
|
|
|
case ChangeIsNecronSelected(isSelected) =>
|
|
isNecrons = isSelected
|
|
if(isSelected) {
|
|
mapsLobby.foreach(map => if(map.map == "2p_meeting_of_minds" || map.map == "2p_shrine_of_excellion_[Rem]") map.isBanned = true)
|
|
}else{
|
|
mapsLobby.foreach(map => map.isBanned = false)
|
|
}
|
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
|
|
|
case KickSecondPlayer =>
|
|
if (sender() == host.actorRef) {
|
|
secondPlayer.foreach(player => player.actorRef ! LobbyFatal("You were kicked from lobby!"))
|
|
secondPlayerReady = false
|
|
secondPlayer = None
|
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
|
}
|
|
|
|
case MessageForLobby(message) =>
|
|
if (sender() == host.actorRef) {
|
|
users.foreach(_ ! SendMessage(Message(host.name, message)))
|
|
}else if (secondPlayer.exists(sp => sp.actorRef == sender())){
|
|
users.foreach(_ ! SendMessage(Message(secondPlayer.get.name, message)))
|
|
}
|
|
case JoinLobbyAsPlayer(sp) =>
|
|
logger.info(s"User ${sender.path.name} join lobby ${self.path.name} as player")
|
|
if (secondPlayer.isEmpty) {
|
|
secondPlayer = Some(sp)
|
|
users = users + sp.actorRef
|
|
sp.actorRef.tell(
|
|
SetUserAsSecondPlayer(getLobbyInfoResponse), this.self)
|
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
|
} else {
|
|
sp.actorRef ! LobbyFatal("Lobby already full")
|
|
}
|
|
|
|
case WatchLobby(_) =>
|
|
// add the watcher to the list
|
|
users = users + sender
|
|
sender ! SetUserAsObs(getLobbyInfoResponse)
|
|
case LeaveLobby =>
|
|
users = users - sender
|
|
if(host.actorRef == sender()){
|
|
users.foreach(_ ! HostLeaveLobby)
|
|
context.stop(self)
|
|
}else if(secondPlayer.exists(_.actorRef == sender())){
|
|
secondPlayerReady = false
|
|
secondPlayer = None
|
|
if(status == Draft()){
|
|
users.foreach(_ ! SecondPlayerLeaveLobby)
|
|
context.stop(self)
|
|
}else {
|
|
users.foreach(_ ! RefreshLobbyInfo(getLobbyInfoResponse))
|
|
}
|
|
}
|
|
if (users.isEmpty) {
|
|
logger.info(s"Stop lobby ${self.path.name}")
|
|
context.stop(self)
|
|
}
|
|
case InfoQuery =>
|
|
logger.info(s"Info query for lobby ${self.path.name} and host ${host.actorRef.path.name}")
|
|
sender ! RefreshLobbyInfo(getLobbyInfoResponse)
|
|
}
|
|
|
|
private def getLobbyInfoResponse: LobbyInfo = {
|
|
val user2Name = secondPlayer.map(_.name).getOrElse("")
|
|
LobbyInfo(
|
|
UserInfo(host.name, firstPlayerReady),
|
|
UserInfo(user2Name, secondPlayerReady),
|
|
self.path.name,
|
|
status.toString(),
|
|
playerTurn,
|
|
lobbyType.toString(),
|
|
isNecrons,
|
|
mapsLobby)
|
|
}
|
|
}
|
|
|
|
case class BanMap(mapName: String)
|
|
|
|
case class MapsUpdate(maps: Set[String])
|
|
|
|
case class CreateLobby(userName: String)
|
|
|
|
case class JoinLobbyAsPlayer(lobbyUser: LobbyUser)
|
|
|
|
case object KickSecondPlayer
|
|
|
|
case class WatchLobby(lobbyName: String)
|
|
|
|
case object LeaveLobby
|
|
|
|
case object SetReady
|
|
|
|
case object SetNotReady
|
|
|
|
case class MessageForLobby(message: String)
|
|
|
|
case class ChangeLobbyType(lobbyType: String)
|
|
|
|
case class ChangeIsNecronSelected(isSelected: Boolean)
|
|
|
|
case object InfoQuery
|
|
|
|
case class UserInfo(name: String, isReady: Boolean)
|
|
|
|
case class LobbyInfo(user1Info: UserInfo,
|
|
user2Info: UserInfo,
|
|
lobbyActorName: String,
|
|
status: String,
|
|
playerTurn: BigDecimal,
|
|
selectedType: String,
|
|
isNecrons: Boolean,
|
|
maps: Set[DeciderMap])
|
|
|
|
class LobbyStatus
|
|
|
|
sealed case class NotStarted() extends LobbyStatus
|
|
sealed case class Draft() extends LobbyStatus
|
|
sealed case class Finish() extends LobbyStatus
|
|
|
|
class LobbyType
|
|
|
|
sealed case class Last3() extends LobbyType
|
|
sealed case class Last5() extends LobbyType
|
|
sealed case class Superfinal() extends LobbyType
|
|
sealed case class LooserPick() extends LobbyType |