Skip to content

Commit

Permalink
playban immediate feedback
Browse files Browse the repository at this point in the history
It warns players before they get playbanned,
if they chose to ignore the warnings.

But more importantly it informs their opponents
that measures are effectively taken against
bad sportmanship behaviours.
Hopefully they'll stop assuming otherwise and
complaining in public boards.
  • Loading branch information
ornicar committed Mar 10, 2018
1 parent 198cf6f commit 29d54bd
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 12 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ lazy val practice = module("practice", Seq(common, db, memo, user, study)).setti
libraryDependencies ++= provided(play.api, reactivemongo.driver)
)

lazy val playban = module("playban", Seq(common, db, game, message)).settings(
lazy val playban = module("playban", Seq(common, db, game, message, chat)).settings(
libraryDependencies ++= provided(play.api, reactivemongo.driver)
)

Expand Down
10 changes: 8 additions & 2 deletions modules/chat/src/main/ChatApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,16 @@ final class ChatApi(

def clear(chatId: Chat.Id) = coll.remove($id(chatId)).void

def system(chatId: Chat.Id, text: String) = {
def system(chatId: Chat.Id, text: String): Funit = {
val line = UserLine(systemUserId, text, troll = false, deleted = false)
pushLine(chatId, line) >>-
lilaBus.publish(actorApi.ChatLine(chatId, line), channelOf(chatId)) inject line.some
lilaBus.publish(actorApi.ChatLine(chatId, line), channelOf(chatId))
}

// like system, but not persisted.
def volatile(chatId: Chat.Id, text: String): Unit = {
val line = UserLine(systemUserId, text, troll = false, deleted = false)
lilaBus.publish(actorApi.ChatLine(chatId, line), channelOf(chatId))
}

def timeout(chatId: Chat.Id, modId: String, userId: String, reason: ChatTimeout.Reason, local: Boolean): Funit =
Expand Down
10 changes: 10 additions & 0 deletions modules/playban/src/main/Env.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import com.typesafe.config.Config
final class Env(
config: Config,
messenger: lila.message.MessageApi,
chatApi: lila.chat.ChatApi,
lightUser: lila.common.LightUser.Getter,
bus: lila.common.Bus,
db: lila.db.Env
) {
Expand All @@ -14,9 +16,15 @@ final class Env(
}
import settings._

private lazy val feedback = new PlaybanFeedback(
chatApi = chatApi,
lightUser = lightUser
)

lazy val api = new PlaybanApi(
coll = db(CollectionPlayban),
sandbag = new SandbagWatch(messenger),
feedback = feedback,
bus = bus
)
}
Expand All @@ -26,6 +34,8 @@ object Env {
lazy val current: Env = "playban" boot new Env(
config = lila.common.PlayApp loadConfig "playban",
messenger = lila.message.Env.current.api,
chatApi = lila.chat.Env.current.api,
lightUser = lila.user.Env.current.lightUserApi.async,
bus = lila.common.PlayApp.system.lilaBus,
db = lila.db.Env.current
)
Expand Down
26 changes: 17 additions & 9 deletions modules/playban/src/main/PlaybanApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import lila.user.{ User, UserRepo }
final class PlaybanApi(
coll: Coll,
sandbag: SandbagWatch,
feedback: PlaybanFeedback,
bus: lila.common.Bus
) {

Expand All @@ -37,16 +38,22 @@ final class PlaybanApi(
blameable(game) flatMap { _ ?? f }

def abort(pov: Pov, isOnGame: Set[Color]): Funit = IfBlameable(pov.game) {
pov.player.userId.ifTrue(isOnGame(pov.opponent.color)) ?? save(Outcome.Abort)
pov.player.userId.ifTrue(isOnGame(pov.opponent.color)) ?? { userId =>
save(Outcome.Abort, userId) >>- feedback.abort(pov)
}
}

def noStart(pov: Pov): Funit = IfBlameable(pov.game) {
pov.player.userId ?? save(Outcome.NoPlay)
pov.player.userId ?? { userId =>
save(Outcome.NoPlay, userId) >>- feedback.noStart(pov)
}
}

def rageQuit(game: Game, quitterColor: Color): Funit =
sandbag(game, quitterColor) >> IfBlameable(game) {
game.player(quitterColor).userId ?? save(Outcome.RageQuit)
game.player(quitterColor).userId ?? { userId =>
save(Outcome.RageQuit, userId) >>- feedback.rageQuit(Pov(game, quitterColor))
}
}

def flag(game: Game, flaggerColor: Color): Funit = {
Expand All @@ -61,7 +68,7 @@ final class PlaybanApi(
seconds = nowSeconds - game.movedAt.getSeconds
limit <- unreasonableTime
if seconds >= limit
} yield save(Outcome.Sitting)(userId)
} yield save(Outcome.Sitting, userId) >>- feedback.sitting(Pov(game, flaggerColor))

// flagged after waiting a short time;
// but the previous move used a long time.
Expand All @@ -72,7 +79,7 @@ final class PlaybanApi(
lastMovetime <- movetimes.lastOption
limit <- unreasonableTime
if lastMovetime.toSeconds >= limit
} yield save(Outcome.SitMoving)(userId)
} yield save(Outcome.SitMoving, userId) >>- feedback.sitting(Pov(game, flaggerColor))

sandbag(game, flaggerColor) flatMap { isSandbag =>
IfBlameable(game) {
Expand All @@ -90,15 +97,16 @@ final class PlaybanApi(
w <- winner
loserId <- game.player(!w).userId
} yield {
if (Status.NoStart is status) save(Outcome.NoPlay)(loserId)
if (Status.NoStart is status) save(Outcome.NoPlay, loserId) >>- feedback.noStart(Pov(game, !w))
else goodOrSandbag(game, !w, isSandbag)
})
}
}

private def goodOrSandbag(game: Game, color: Color, isSandbag: Boolean): Funit =
game.player(color).userId ?? {
save(if (isSandbag) Outcome.Sandbag else Outcome.Good)
game.player(color).userId ?? { userId =>
if (isSandbag) feedback.sandbag(Pov(game, color))
save(if (isSandbag) Outcome.Sandbag else Outcome.Good, userId)
}

def currentBan(userId: User.ID): Fu[Option[TempBan]] = coll.find(
Expand Down Expand Up @@ -135,7 +143,7 @@ final class PlaybanApi(
}(scala.collection.breakOut)
}

private def save(outcome: Outcome): User.ID => Funit = userId => {
private def save(outcome: Outcome, userId: User.ID): Funit = {
lila.mon.playban.outcome(outcome.key)()
coll.findAndUpdate(
selector = $id(userId),
Expand Down
30 changes: 30 additions & 0 deletions modules/playban/src/main/PlaybanFeedback.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package lila.playban

import lila.chat.{ Chat, ChatApi }
import lila.game.Pov

private final class PlaybanFeedback(
chatApi: ChatApi,
lightUser: lila.common.LightUser.Getter
) {

private val tempBan = "will result in a temporary ban."

def abort(pov: Pov): Unit = tell(pov, s"Warning, {user}: aborting too many games $tempBan")

def noStart(pov: Pov): Unit = tell(pov, s"Warning, {user}: failing to start games $tempBan")

def rageQuit(pov: Pov): Unit = tell(pov, s"Warning, {user}: leaving games without resigning $tempBan")

def sitting(pov: Pov): Unit = tell(pov, s"Warning, {user}: letting time run out instead of resigning $tempBan")

def sandbag(pov: Pov): Unit = tell(pov, s"Warning, {user}: losing games on purpose will result in a ban.")

private def tell(pov: Pov, template: String): Unit =
pov.player.userId foreach { userId =>
lightUser(userId) foreach { light =>
val message = template.replace("{user}", light.fold(userId)(_.name))
chatApi.userChat.volatile(Chat.Id(pov.gameId), message)
}
}
}

0 comments on commit 29d54bd

Please sign in to comment.