diff --git a/src/main/scala/com/github/unchama/seichiassist/SeichiAssist.scala b/src/main/scala/com/github/unchama/seichiassist/SeichiAssist.scala index f7359a6b8b..6840a95ae9 100644 --- a/src/main/scala/com/github/unchama/seichiassist/SeichiAssist.scala +++ b/src/main/scala/com/github/unchama/seichiassist/SeichiAssist.scala @@ -63,6 +63,7 @@ import com.github.unchama.seichiassist.subsystems.autosave.application.SystemCon import com.github.unchama.seichiassist.subsystems.breakcount.{BreakCountAPI, BreakCountReadAPI} import com.github.unchama.seichiassist.subsystems.breakcountbar.BreakCountBarAPI import com.github.unchama.seichiassist.subsystems.breakskilltargetconfig.BreakSkillTargetConfigAPI +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.BreakSkillTriggerConfigAPI import com.github.unchama.seichiassist.subsystems.buildcount.BuildCountAPI import com.github.unchama.seichiassist.subsystems.discordnotification.DiscordNotificationAPI import com.github.unchama.seichiassist.subsystems.donate.DonatePremiumPointAPI @@ -495,6 +496,9 @@ class SeichiAssist extends JavaPlugin() { lazy val breakSkillTargetConfigSystem: subsystems.breakskilltargetconfig.System[IO, Player] = subsystems.breakskilltargetconfig.System.wired[IO, SyncIO].unsafeRunSync() + lazy val breakSkillTriggerConfigSystem: subsystems.breakskilltriggerconfig.System[IO, Player] = + subsystems.breakskilltriggerconfig.System.wired[IO, SyncIO].unsafeRunSync() + /* TODO: mineStackSystemは本来privateであるべきだが、mineStackにアイテムを格納するAPIが現状の BreakUtilの実装から呼び出されている都合上やむを得ずpublicになっている。*/ lazy val mineStackSystem: subsystems.minestack.System[IO, Player, ItemStack] = @@ -562,6 +566,7 @@ class SeichiAssist extends JavaPlugin() { openirontrapdoor.System.wired, gridRegionSystem, breakSkillTargetConfigSystem, + breakSkillTriggerConfigSystem, joinAndQuitMessenger, elevatorSystem, blockLiquidStreamSystem, @@ -746,6 +751,8 @@ class SeichiAssist extends JavaPlugin() { implicit val gridRegionAPI: GridRegionAPI[IO, Player, Location] = gridRegionSystem.api implicit val breakSkillTargetConfigAPI: BreakSkillTargetConfigAPI[IO, Player] = breakSkillTargetConfigSystem.api + implicit val breakSkillTriggerConfigAPI: BreakSkillTriggerConfigAPI[IO, Player] = + breakSkillTriggerConfigSystem.api implicit val playerHeadSkinAPI: PlayerHeadSkinAPI[IO, Player] = playerHeadSkinSystem.api val menuRouter = TopLevelRouter.apply diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/TopLevelRouter.scala b/src/main/scala/com/github/unchama/seichiassist/menus/TopLevelRouter.scala index c7b44baa6c..7856db1575 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/TopLevelRouter.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/TopLevelRouter.scala @@ -31,6 +31,7 @@ import com.github.unchama.seichiassist.subsystems.breakcount.BreakCountAPI import com.github.unchama.seichiassist.subsystems.breakcount.domain.SeichiAmountData import com.github.unchama.seichiassist.subsystems.breakcountbar.BreakCountBarAPI import com.github.unchama.seichiassist.subsystems.breakskilltargetconfig.BreakSkillTargetConfigAPI +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.BreakSkillTriggerConfigAPI import com.github.unchama.seichiassist.subsystems.buildcount.domain.playerdata.BuildAmountData import com.github.unchama.seichiassist.subsystems.discordnotification.DiscordNotificationAPI import com.github.unchama.seichiassist.subsystems.donate.DonatePremiumPointAPI @@ -104,6 +105,7 @@ object TopLevelRouter { fairySpeechAPI: FairySpeechAPI[IO, Player], gridRegionAPI: GridRegionAPI[IO, Player, Location], breakSkillTargetConfigAPI: BreakSkillTargetConfigAPI[IO, Player], + breakSkillTriggerConfigAPI: BreakSkillTriggerConfigAPI[IO, Player], playerHeadSkinAPI: PlayerHeadSkinAPI[IO, Player] ): TopLevelRouter[IO] = new TopLevelRouter[IO] { import assortedRankingApi._ diff --git a/src/main/scala/com/github/unchama/seichiassist/menus/skill/PassiveSkillMenu.scala b/src/main/scala/com/github/unchama/seichiassist/menus/skill/PassiveSkillMenu.scala index a463c0a50e..2bdb75b292 100644 --- a/src/main/scala/com/github/unchama/seichiassist/menus/skill/PassiveSkillMenu.scala +++ b/src/main/scala/com/github/unchama/seichiassist/menus/skill/PassiveSkillMenu.scala @@ -13,6 +13,8 @@ import com.github.unchama.seichiassist.menus.stickmenu.FirstPage import com.github.unchama.seichiassist.subsystems.breakcount.BreakCountAPI import com.github.unchama.seichiassist.subsystems.breakskilltargetconfig.BreakSkillTargetConfigAPI import com.github.unchama.seichiassist.subsystems.breakskilltargetconfig.domain.BreakSkillTargetConfigKey +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.BreakSkillTriggerConfigAPI +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.domain.BreakSkillTriggerConfigKey import com.github.unchama.seichiassist.subsystems.playerheadskin.PlayerHeadSkinAPI import com.github.unchama.targetedeffect._ import com.github.unchama.targetedeffect.commandsender.MessageEffect @@ -34,6 +36,7 @@ object PassiveSkillMenu extends Menu { class Environment( implicit val breakCountApi: BreakCountAPI[IO, SyncIO, Player], implicit val breakSkillTargetConfigAPI: BreakSkillTargetConfigAPI[IO, Player], + implicit val breakSkillTriggerConfigAPI: BreakSkillTriggerConfigAPI[IO, Player], val ioCanOpenFirstPage: IO CanOpen FirstPage.type, implicit val playerHeadSkinAPI: PlayerHeadSkinAPI[IO, Player] ) diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/BreakSkillTriggerConfigAPI.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/BreakSkillTriggerConfigAPI.scala new file mode 100644 index 0000000000..1df97cf935 --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/BreakSkillTriggerConfigAPI.scala @@ -0,0 +1,28 @@ +package com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig + +import cats.data.Kleisli +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.domain.BreakSkillTriggerConfigKey + +trait BreakSkillTriggerConfigAPI[F[_], Player] { + + /** + * @return 破壊トリガをトグルする作用 + */ + def toggleBreakSkillTriggerConfig( + configKey: BreakSkillTriggerConfigKey + ): Kleisli[F, Player, Unit] + + /** + * @return 現在の破壊トリガを取得する作用 + */ + def breakSkillTriggerConfig(player: Player, configKey: BreakSkillTriggerConfigKey): F[Boolean] + +} + +object BreakSkillTriggerConfigAPI { + + def apply[F[_], Player]( + implicit ev: BreakSkillTriggerConfigAPI[F, Player] + ): BreakSkillTriggerConfigAPI[F, Player] = ev + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/System.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/System.scala new file mode 100644 index 0000000000..4b13276b9c --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/System.scala @@ -0,0 +1,66 @@ +package com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig + +import cats.data.Kleisli +import cats.effect.SyncEffect +import com.github.unchama.datarepository.bukkit.player.BukkitRepositoryControls +import com.github.unchama.generic.ContextCoercion +import com.github.unchama.seichiassist.meta.subsystem.Subsystem +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.application.repository.BreakSkillTriggerConfigRepositoryDefinition +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.domain.{ + BreakSkillTriggerConfigKey, + BreakSkillTriggerConfigPersistence +} +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.persistence.JdbcBreakSkillTriggerConfigPersistence +import org.bukkit.entity.Player + +trait System[F[_], Player] extends Subsystem[F] { + val api: BreakSkillTriggerConfigAPI[F, Player] +} + +object System { + + import cats.implicits._ + + def wired[F[_], G[_]: SyncEffect: ContextCoercion[*[_], F]]: G[System[F, Player]] = { + implicit val breakSkillTriggerConfigPersistence: BreakSkillTriggerConfigPersistence[G] = + new JdbcBreakSkillTriggerConfigPersistence[G] + + for { + breakSkillTriggerConfigRepositoryControls <- BukkitRepositoryControls.createHandles( + BreakSkillTriggerConfigRepositoryDefinition.withContext[G, Player] + ) + } yield { + val breakSkillTriggerConfigRepository = breakSkillTriggerConfigRepositoryControls.repository + + new System[F, Player] { + override val api: BreakSkillTriggerConfigAPI[F, Player] = + new BreakSkillTriggerConfigAPI[F, Player] { + override def toggleBreakSkillTriggerConfig( + configKey: BreakSkillTriggerConfigKey + ): Kleisli[F, Player, Unit] = + Kleisli { player => + ContextCoercion( + breakSkillTriggerConfigRepository(player) + .update(_.toggleBreakSkillTriggerConfig(configKey)) + ) + } + + override def breakSkillTriggerConfig( + player: Player, + configKey: BreakSkillTriggerConfigKey + ): F[Boolean] = + ContextCoercion( + breakSkillTriggerConfigRepository(player) + .get + .map(_.breakSkillTriggerConfig(configKey)) + ) + } + + override val managedRepositoryControls: Seq[BukkitRepositoryControls[F, _]] = Seq( + breakSkillTriggerConfigRepositoryControls.coerceFinalizationContextTo[F] + ) + } + } + } + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/application/BreakSkillTriggerConfigRepositoryDefinition.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/application/BreakSkillTriggerConfigRepositoryDefinition.scala new file mode 100644 index 0000000000..89339ce26d --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/application/BreakSkillTriggerConfigRepositoryDefinition.scala @@ -0,0 +1,23 @@ +package com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.application.repository + +import cats.effect.Sync +import cats.effect.concurrent.Ref +import com.github.unchama.datarepository.definitions.RefDictBackedRepositoryDefinition +import com.github.unchama.datarepository.template.RepositoryDefinition +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.domain.{ + BreakSkillTriggerConfig, + BreakSkillTriggerConfigPersistence +} + +object BreakSkillTriggerConfigRepositoryDefinition { + + def withContext[F[_]: Sync, Player]( + implicit persistence: BreakSkillTriggerConfigPersistence[F] + ): RepositoryDefinition[F, Player, Ref[F, BreakSkillTriggerConfig]] = + RefDictBackedRepositoryDefinition + .usingUuidRefDict[F, Player, BreakSkillTriggerConfig](persistence)( + BreakSkillTriggerConfig.initial + ) + .toRefRepository + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfig.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfig.scala new file mode 100644 index 0000000000..8111bc8286 --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfig.scala @@ -0,0 +1,28 @@ +package com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.domain + +case class BreakSkillTriggerConfig(config: Map[BreakSkillTriggerConfigKey, Boolean]) { + + /** + * @return `configKey`の破壊トリガをトグルする + */ + def toggleBreakSkillTriggerConfig( + configKey: BreakSkillTriggerConfigKey + ): BreakSkillTriggerConfig = + this.copy(this.config + (configKey -> !this.config.getOrElse(configKey, false))) + + /** + * @return 現在の破壊トリガを取得する + */ + def breakSkillTriggerConfig(configKey: BreakSkillTriggerConfigKey): Boolean = + this.config.getOrElse(configKey, false) + +} + +object BreakSkillTriggerConfig { + + /** + * [[BreakSkillTriggerConfig]]の初期値 + */ + val initial: BreakSkillTriggerConfig = BreakSkillTriggerConfig(Map.empty) + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfigKey.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfigKey.scala new file mode 100644 index 0000000000..293979b2d0 --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfigKey.scala @@ -0,0 +1,21 @@ +package com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.domain + +import enumeratum.{Enum, EnumEntry} + +/** + * トリガ条件の集合を表現する。 + * これらの値は整地スキルでブロックを破壊する際に、 + * プレイヤーの設定に応じて使われる。 + */ +sealed trait BreakSkillTriggerConfigKey extends EnumEntry + +object BreakSkillTriggerConfigKey extends Enum[BreakSkillTriggerConfigKey] { + + val values: IndexedSeq[BreakSkillTriggerConfigKey] = findValues + + /** + * マナを消費しきった場合にブロックを破壊するかどうか + */ + case object ManaFullyConsumed extends BreakSkillTriggerConfigKey + +} diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfigPersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfigPersistence.scala new file mode 100644 index 0000000000..938ba6b70f --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/domain/BreakSkillTriggerConfigPersistence.scala @@ -0,0 +1,7 @@ +package com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.domain + +import com.github.unchama.generic.RefDict + +import java.util.UUID + +trait BreakSkillTriggerConfigPersistence[F[_]] extends RefDict[F, UUID, BreakSkillTriggerConfig] diff --git a/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/infrastructure/JdbcBreakSkillTriggerConfigPersistence.scala b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/infrastructure/JdbcBreakSkillTriggerConfigPersistence.scala new file mode 100644 index 0000000000..1b656ca440 --- /dev/null +++ b/src/main/scala/com/github/unchama/seichiassist/subsystems/breakskilltriggerconfig/infrastructure/JdbcBreakSkillTriggerConfigPersistence.scala @@ -0,0 +1,52 @@ +package com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.persistence + +import cats.effect.Sync +import com.github.unchama.seichiassist.subsystems.breakskilltriggerconfig.domain.{ + BreakSkillTriggerConfig, + BreakSkillTriggerConfigKey, + BreakSkillTriggerConfigPersistence +} +import scalikejdbc.{DB, scalikejdbcSQLInterpolationImplicitDef} + +import java.util.UUID + +class JdbcBreakSkillTriggerConfigPersistence[F[_]: Sync] + extends BreakSkillTriggerConfigPersistence[F] { + + override def read(key: UUID): F[Option[BreakSkillTriggerConfig]] = Sync[F].delay { + val config = DB.readOnly { implicit session => + sql"SELECT trigger_category, do_not_break FROM player_break_trigger_preference WHERE uuid = ${key.toString}" + .map { rs => + BreakSkillTriggerConfigKey.withNameOption(rs.string("trigger_category")).map { + flagName => flagName -> rs.boolean("do_not_break") + } + } + .toList() + .flatten + .toMap + } + + Some(BreakSkillTriggerConfig(config)) + } + + override def write(key: UUID, value: BreakSkillTriggerConfig): F[Unit] = Sync[F].delay { + DB.localTx { implicit session => + val uuid = key.toString + val batchParams = + value + .config + .map { + case (triggerCategory, doNotBreak) => + Seq(uuid, triggerCategory.entryName, doNotBreak) + } + .toSeq + + sql"""INSERT INTO player_break_trigger_preference (uuid, trigger_category, do_not_break) + | VALUES (?, ?, ?) + | ON DUPLICATE KEY UPDATE + | do_not_break = VALUE(do_not_break) + """.stripMargin.batch(batchParams: _*).apply[List]() + } + } + +}