diff --git a/build.gradle.kts b/build.gradle.kts index cf771a6..1c2c1be 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,16 +3,18 @@ plugins { id("com.gradleup.shadow") version "9.2.2" id("xyz.jpenilla.run-paper") version "3.0.2" id("io.papermc.paperweight.userdev") version "2.0.0-beta.19" + id("org.jlleitschuh.gradle.ktlint") version "14.0.1" } group = "fr.azur" -version = "1.1-SNAPSHOT" +val version: String by project val minecraftVersion: String by project val paperVersion: String by project val skinRestorerVersion: String by project val voiceChatVersion: String by project val voiceChatApiVersion: String by project +val luckPermsVersion: String by project repositories { mavenCentral() @@ -34,11 +36,11 @@ repositories { dependencies { paperweight.paperDevBundle("$minecraftVersion-$paperVersion") - - implementation("net.skinsrestorer:skinsrestorer-api:$skinRestorerVersion") - implementation("de.maxhenkel.voicechat:voicechat-api:$voiceChatApiVersion") + compileOnly("net.skinsrestorer:skinsrestorer-api:$skinRestorerVersion") + compileOnly("de.maxhenkel.voicechat:voicechat-api:$voiceChatApiVersion") implementation(kotlin("stdlib-jdk8")) + implementation(kotlin("reflect")) } val targetJavaVersion = 21 @@ -49,8 +51,9 @@ kotlin { tasks { runServer { downloadPlugins { - modrinth("plasmo-voice", "bukkit-$voiceChatVersion") modrinth("skinsrestorer", skinRestorerVersion) + modrinth("luckperms", luckPermsVersion) + modrinth("simple-voice-chat", voiceChatVersion) } minecraftVersion(minecraftVersion) } @@ -69,8 +72,5 @@ tasks { archiveBaseName.set("tcoww") minimize() - -// exclude("META-INF/*.kotlin_module") -// exclude("META-INF/*.version") } -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index 8121979..9ab8def 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,7 @@ +version=1.2.0 paperVersion=R0.1-SNAPSHOT -minecraftVersion=1.21.8 -skinRestorerVersion=15.8.2 +minecraftVersion=1.21.10 +skinRestorerVersion=15.9.0 voiceChatApiVersion=2.6.0 -voiceChatVersion=2.6.6 \ No newline at end of file +voiceChatVersion=2.6.6 +luckPermsVersion=5.5.17 \ No newline at end of file diff --git a/src/main/kotlin/fr/azur/tcoww/Tcoww.kt b/src/main/kotlin/fr/azur/tcoww/Tcoww.kt index 7ea74cc..2b2af9d 100644 --- a/src/main/kotlin/fr/azur/tcoww/Tcoww.kt +++ b/src/main/kotlin/fr/azur/tcoww/Tcoww.kt @@ -1,50 +1,64 @@ package fr.azur.tcoww import de.maxhenkel.voicechat.api.BukkitVoicechatService -import fr.azur.tcoww.events.GameEvent +import fr.azur.tcoww.events.GameEvents +import fr.azur.tcoww.events.PowerEvents import fr.azur.tcoww.events.ToolsEvents -import fr.azur.tcoww.roles.* -import fr.azur.tcoww.utils.Skin -import fr.azur.tcoww.voicechat.VoiceChatPlugin -import net.skinsrestorer.api.SkinsRestorer -import net.skinsrestorer.api.SkinsRestorerProvider +import fr.azur.tcoww.events.UIEvents +import fr.azur.tcoww.roles.Child +import fr.azur.tcoww.roles.FortuneTeller +import fr.azur.tcoww.roles.Hunter +import fr.azur.tcoww.roles.Role +import fr.azur.tcoww.roles.Villager +import fr.azur.tcoww.roles.Werewolf +import fr.azur.tcoww.roles.Witch +import fr.azur.tcoww.utils.VoiceChatPlugin +import fr.azur.tcoww.utils.skins.Manager +import fr.azur.tcoww.utils.skins.WerewolfSkin +import org.bukkit.configuration.serialization.ConfigurationSerialization import org.bukkit.plugin.java.JavaPlugin +import org.bukkit.scoreboard.Team -class Tcoww : JavaPlugin() { - private lateinit var skinsRestorer: SkinsRestorer - private lateinit var skinManager: Skin - +object Tcoww : JavaPlugin() { override fun onEnable() { - saveResource("config.yml", false) + ConfigurationSerialization.registerClass(WerewolfSkin::class.java) + saveDefaultConfig() - skinsRestorer = SkinsRestorerProvider.get() - skinManager = Skin(this, skinsRestorer) + Manager.handle() - server.pluginManager.registerEvents(ToolsEvents(this), this) - server.pluginManager.registerEvents(GameEvent(this, skinManager), this) + server.pluginManager.apply { + registerEvents(UIEvents, this@Tcoww) + registerEvents(GameEvents, this@Tcoww) + registerEvents(PowerEvents, this@Tcoww) + registerEvents(ToolsEvents, this@Tcoww) + } - val vcservice = server.servicesManager.load(BukkitVoicechatService::class.java) - vcservice?.registerPlugin(VoiceChatPlugin()) + val service = server.servicesManager.load(BukkitVoicechatService::class.java) + service?.registerPlugin(VoiceChatPlugin) registerRoles() + + val mainScoreboard = server.scoreboardManager.mainScoreboard + if (mainScoreboard.getTeam("NoCollide") == null) { + val team = server.scoreboardManager.mainScoreboard.registerNewTeam("NoCollision") + team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER) + } } override fun onDisable() { - } fun reload() { this.reloadConfig() - skinManager.reloadSkin() } private fun registerRoles() { - Role.registerRole(Villager()) - Role.registerRole(Werewolf()) - Role.registerRole(Child()) - Role.registerRole(FortuneTeller()) - Role.registerRole(Hunter()) - Role.registerRole(Witch()) + Role.registerRole(Villager) + Role.registerRole(Werewolf) + Role.registerRole(Child) + Role.registerRole(FortuneTeller) + Role.registerRole(Hunter) + Role.registerRole(Witch) } } diff --git a/src/main/kotlin/fr/azur/tcoww/TcowwBootstrap.kt b/src/main/kotlin/fr/azur/tcoww/TcowwBootstrap.kt index e05c3c2..0f02589 100644 --- a/src/main/kotlin/fr/azur/tcoww/TcowwBootstrap.kt +++ b/src/main/kotlin/fr/azur/tcoww/TcowwBootstrap.kt @@ -1,26 +1,26 @@ package fr.azur.tcoww import fr.azur.tcoww.commands.Exclude -import fr.azur.tcoww.commands.Power import fr.azur.tcoww.commands.GameCommand import fr.azur.tcoww.commands.ReloadCommands -import fr.azur.tcoww.commands.TimeGest import fr.azur.tcoww.commands.Tools import fr.azur.tcoww.commands.Vote import io.papermc.paper.plugin.bootstrap.BootstrapContext import io.papermc.paper.plugin.bootstrap.PluginBootstrap import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents -class TcowwBootstrap : PluginBootstrap { +object TcowwBootstrap : PluginBootstrap { override fun bootstrap(context: BootstrapContext) { - context.lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS) { commands -> - commands.registrar().register(Tools().root.build()) - commands.registrar().register(TimeGest().root.build()) - commands.registrar().register(Power().root.build()) - commands.registrar().register(GameCommand().root.build()) - commands.registrar().register(Vote().root.build()) - commands.registrar().register(ReloadCommands().root.build()) - commands.registrar().register(Exclude().root.build()) + context.lifecycleManager.apply { + registerEventHandler(LifecycleEvents.COMMANDS) { commands -> + commands.registrar().apply { + register(Tools.root) + register(GameCommand.root) + commands.registrar().register(Vote.root) + register(ReloadCommands.root) + commands.registrar().register(Exclude.root) + } + } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/fr/azur/tcoww/commands/Exclude.kt b/src/main/kotlin/fr/azur/tcoww/commands/Exclude.kt index 145b77b..4c596e5 100644 --- a/src/main/kotlin/fr/azur/tcoww/commands/Exclude.kt +++ b/src/main/kotlin/fr/azur/tcoww/commands/Exclude.kt @@ -1,40 +1,32 @@ package fr.azur.tcoww.commands import com.mojang.brigadier.Command -import com.mojang.brigadier.builder.LiteralArgumentBuilder import fr.azur.tcoww.game.Game -import io.papermc.paper.command.brigadier.CommandSourceStack +import fr.azur.tcoww.utils.Players.kill import io.papermc.paper.command.brigadier.Commands import io.papermc.paper.command.brigadier.argument.ArgumentTypes import io.papermc.paper.command.brigadier.argument.resolvers.PlayerProfileListResolver import org.bukkit.Bukkit -import org.bukkit.GameMode - -class Exclude { - val root: LiteralArgumentBuilder = Commands.literal("exclude") - .requires { sender -> - sender.sender.isOp - }.then( - Commands.literal("start") - .then( - Commands.argument("players", ArgumentTypes.playerProfiles()).executes { ctx -> - val targetResolver = ctx.getArgument("players", PlayerProfileListResolver::class.java) - val target = targetResolver.resolve(ctx.source).first() - val uuid = target.id - if (uuid != null) { - val player = Bukkit.getPlayer(uuid) - if (player != null) { - val game = Game.current ?: return@executes Command.SINGLE_SUCCESS - player.gameMode = GameMode.SPECTATOR - player.isInvulnerable = false - game.playersMutable.remove(player) - } +object Exclude { + val root = + Commands + .literal("exclude") + .requires { sender -> + sender.sender.isOp + }.then( + Commands.argument("players", ArgumentTypes.playerProfiles()).executes { ctx -> + val targetResolver = ctx.getArgument("players", PlayerProfileListResolver::class.java) + val target = targetResolver.resolve(ctx.source).first() + val uuid = target.id + if (uuid != null) { + val player = Bukkit.getPlayer(uuid) + if (player != null) { + val game = Game.current ?: return@executes Command.SINGLE_SUCCESS + player.kill() } - Command.SINGLE_SUCCESS } - - ) - ) - -} \ No newline at end of file + Command.SINGLE_SUCCESS + }, + ).build() +} diff --git a/src/main/kotlin/fr/azur/tcoww/commands/GameCommand.kt b/src/main/kotlin/fr/azur/tcoww/commands/GameCommand.kt index c68ba3a..964f9f6 100644 --- a/src/main/kotlin/fr/azur/tcoww/commands/GameCommand.kt +++ b/src/main/kotlin/fr/azur/tcoww/commands/GameCommand.kt @@ -1,67 +1,90 @@ package fr.azur.tcoww.commands import com.mojang.brigadier.Command -import com.mojang.brigadier.arguments.StringArgumentType -import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.tree.LiteralCommandNode +import fr.azur.tcoww.Tcoww import fr.azur.tcoww.game.Game -import fr.azur.tcoww.roles.Role -import fr.azur.tcoww.roles.Villager -import fr.azur.tcoww.roles.Werewolf +import fr.azur.tcoww.ui.GameConfig import io.papermc.paper.command.brigadier.CommandSourceStack import io.papermc.paper.command.brigadier.Commands -import io.papermc.paper.command.brigadier.argument.ArgumentTypes -import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver +import io.papermc.paper.dialog.Dialog +import io.papermc.paper.registry.data.dialog.ActionButton +import io.papermc.paper.registry.data.dialog.DialogBase +import io.papermc.paper.registry.data.dialog.action.DialogAction +import io.papermc.paper.registry.data.dialog.type.DialogType +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.event.ClickEvent +import net.kyori.adventure.text.format.NamedTextColor import org.bukkit.Bukkit +import org.bukkit.GameMode import org.bukkit.NamespacedKey +import org.bukkit.World +import org.bukkit.entity.Player +import org.bukkit.plugin.Plugin - -class GameCommand { - val root: LiteralArgumentBuilder = Commands.literal("game") - .requires { sender -> - sender.sender.isOp - }.then( - Commands.literal("start") - .then( - Commands.argument("players", ArgumentTypes.players()).then( - Commands.argument("roles", StringArgumentType.greedyString()).suggests { ctx, builder -> - val roleswithoutauto = - Role.registerRoles.filter { role -> role.value !is Villager && role.value !is Werewolf } - val rolessplit = builder.remaining.split(" ") - val startstr = rolessplit.dropLast(1).joinToString(separator = " ") - - roleswithoutauto.forEach { role -> - if (role.key.toString().startsWith(rolessplit.last())) { - builder.suggest("$startstr${if (startstr.isEmpty()) "" else " "}${role.key}") - } - } - if (builder.remaining != "" && !builder.remaining.endsWith(" ")) { - roleswithoutauto.forEach { role -> - builder.suggest("${builder.remaining} ${role.key}") - } - } - builder.buildFuture() - }.executes { ctx -> - val plugin = Bukkit.getPluginManager().getPlugin("tcoww")!! - val targetResolver = ctx.getArgument("players", PlayerSelectorArgumentResolver::class.java) - val targets = targetResolver.resolve(ctx.source) - - val rolesstr = StringArgumentType.getString(ctx, "roles") - val rolessplit = rolesstr.split(" ") - - val roles = rolessplit.map { str -> - Role.registerRoles[NamespacedKey.fromString(str)] - } - val correctrole = roles.filterNotNull() - - Game(plugin, ctx.source.location.world, targets, correctrole) - Command.SINGLE_SUCCESS - } - ) +object GameCommand { + private fun createDialog( + plugin: Plugin, + world: World, + players: Iterable, + roles: Map, + ): Dialog = + Dialog.create { builder -> + builder + .empty() + .base( + DialogBase + .builder(Component.text("Start the Game", NamedTextColor.GREEN)) + .canCloseWithEscape(true) + .build(), + ).type( + DialogType.confirmation( + ActionButton + .builder(Component.text("Start", NamedTextColor.GREEN)) + .action( + DialogAction.staticAction( + ClickEvent.callback { + Game(plugin, world, players, roles) + it.closeDialog() + }, + ), + ).build(), + ActionButton + .builder(Component.text("Cancel", NamedTextColor.RED)) + .action(DialogAction.staticAction(ClickEvent.callback { it.closeDialog() })) + .build(), + ), ) - ).then( - Commands.literal("stop").executes { ctx -> - Game.current?.stopGame(true) - Command.SINGLE_SUCCESS - } - ) -} \ No newline at end of file + } + + val root: LiteralCommandNode = + Commands + .literal("game") + .requires { sender -> + sender.sender.isOp + }.then( + Commands + .literal("start") + .executes { ctx -> + val executor = ctx.source.executor ?: ctx.source.sender + if (executor is Player) { + val players = + Bukkit + .getOnlinePlayers() + .filter { it.gameMode == GameMode.ADVENTURE || it.gameMode == GameMode.SURVIVAL } + val menu = GameConfig(players.size) + executor.openInventory(menu.inventory) + menu.future.thenAccept { + val dialog = createDialog(Tcoww, executor.world, players, it) + executor.showDialog(dialog) + } + } + Command.SINGLE_SUCCESS + }, + ).then( + Commands.literal("stop").executes { ctx -> + Game.current?.stopGame(true) + Command.SINGLE_SUCCESS + }, + ).build() +} diff --git a/src/main/kotlin/fr/azur/tcoww/commands/Power.kt b/src/main/kotlin/fr/azur/tcoww/commands/Power.kt deleted file mode 100644 index dc7242c..0000000 --- a/src/main/kotlin/fr/azur/tcoww/commands/Power.kt +++ /dev/null @@ -1,156 +0,0 @@ -package fr.azur.tcoww.commands - -import com.mojang.brigadier.Command -import com.mojang.brigadier.builder.LiteralArgumentBuilder -import fr.azur.tcoww.game.Game -import fr.azur.tcoww.roles.FortuneTeller -import fr.azur.tcoww.roles.Role -import fr.azur.tcoww.roles.Witch -import fr.azur.tcoww.utils.Stockage -import io.papermc.paper.command.brigadier.CommandSourceStack -import io.papermc.paper.command.brigadier.Commands -import io.papermc.paper.command.brigadier.argument.ArgumentTypes -import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.event.HoverEvent -import net.kyori.adventure.text.format.NamedTextColor -import org.bukkit.Bukkit -import org.bukkit.NamespacedKey -import org.bukkit.entity.Player -import org.bukkit.persistence.PersistentDataType -import org.bukkit.potion.PotionEffect -import org.bukkit.potion.PotionEffectType - -class Power { - val root: LiteralArgumentBuilder = Commands.literal("power") - .requires { ctx -> ctx.sender as? Player != null && Role.getRole(ctx.sender as Player)?.hasPowerCommand == true } - .then( - Commands.literal("kill") - .requires { ctx -> - val player = ctx.executor as? Player ?: return@requires false - val role = Role.getRole(player) - (role is Witch && player.hasPowerItem(1)) - } - .then( - Commands.argument("target", ArgumentTypes.player()) - .suggests { _, builder -> - Game.current?.playersMutable?.forEach { builder.suggest(it.name) } - builder.buildFuture() - } - .executes { ctx -> - val target = ctx.getTargetPlayer("target") ?: return@executes 0 - val player = ctx.source.getPlayer() ?: return@executes 0 - if (Game.current?.playersMutable?.contains(target) == true) { - target.addPotionEffect(PotionEffect(PotionEffectType.WITHER, 600, 4)) - player.removePowerItem(1) - } - Command.SINGLE_SUCCESS - } - ) - ) - .then( - Commands.literal("save") - .requires { ctx -> - val player = ctx.executor as? Player ?: return@requires false - val role = Role.getRole(player) - role is Witch && player.hasPowerItem(2) - } - .then( - Commands.argument("target", ArgumentTypes.player()) - .executes { ctx -> - val target = ctx.getTargetPlayer("target") ?: return@executes 0 - val player = ctx.source.getPlayer() ?: return@executes 0 - if (Game.current?.playersMutable?.contains(target) == true && - target.persistentDataContainer.get( - NamespacedKey("tcoww", "dead"), - PersistentDataType.BOOLEAN - ) == true - ) { - target.persistentDataContainer.set( - NamespacedKey("tcoww", "dead"), - PersistentDataType.BOOLEAN, - false - ) - Stockage.backLocation[target.uniqueId]?.let { target.teleport(it) } - target.isInvulnerable = false - target.sendMessage(Component.text("Vous avez été résucité.").color(NamedTextColor.AQUA)) - player.sendMessage( - Component.text("Vous avez résuciter ").color(NamedTextColor.AQUA) - .append(player.displayName()) - ) - player.removePowerItem(2) - } - Command.SINGLE_SUCCESS - } - ) - ) - .then( - Commands.literal("view") - .requires { ctx -> - val player = ctx.executor as? Player ?: return@requires false - val role = Role.getRole(player) - role is FortuneTeller && player.hasPowerItem(4) - } - .then( - Commands.argument("target", ArgumentTypes.player()) - .suggests { _, builder -> - Game.current?.playersMutable?.forEach { builder.suggest(it.name) } - builder.buildFuture() - } - .executes { ctx -> - val target = ctx.getTargetPlayer("target") ?: return@executes 0 - val player = ctx.source.getPlayer() ?: return@executes 0 - val plugin = Bukkit.getPluginManager().getPlugin("tcoww") ?: return@executes 0 - if (Game.current?.playersMutable?.contains(target) == true) { - val item = player.getPowerItem(4) ?: return@executes 0 - - val timeGestion = Game.current!!.timeGestion - val cooldown = - ((timeGestion.dayDuration + timeGestion.voteDuration + timeGestion.nightDuration + timeGestion.crepuscularDuration - 30) * 2) * 20 - - val cloneditem = item.clone() - - player.inventory.remove(item) - - Bukkit.getScheduler().runTaskLater(plugin, Runnable { - player.inventory.addItem(cloneditem) - }, cooldown.toLong()) - - val targetrole = Role.getRole(target) - - player.sendMessage( - target.displayName().append(Component.text(" est ")) - .append( - (targetrole?.displayName ?: Component.text("Inconnu").hoverEvent( - HoverEvent.showText( - targetrole?.description ?: Component.empty() - ) - )) - ) - ) - } - Command.SINGLE_SUCCESS - } - ) - ) - - private fun CommandSourceStack.getPlayer(): Player? = (this.executor ?: this.sender) as? Player - - private fun Player.hasPowerItem(id: Int): Boolean = this.inventory.any { - it?.persistentDataContainer?.get(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER) == id - } - - private fun Player.getPowerItem(id: Int) = this.inventory.firstOrNull { - it?.persistentDataContainer?.get(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER) == id - } - - private fun Player.removePowerItem(id: Int) { - val item = getPowerItem(id) ?: return - this.inventory.remove(item) - } - - private fun com.mojang.brigadier.context.CommandContext.getTargetPlayer(name: String): Player? { - val resolver = this.getArgument(name, PlayerSelectorArgumentResolver::class.java) - return resolver.resolve(this.source).firstOrNull() - } -} diff --git a/src/main/kotlin/fr/azur/tcoww/commands/ReloadCommands.kt b/src/main/kotlin/fr/azur/tcoww/commands/ReloadCommands.kt index 827202d..681f33e 100644 --- a/src/main/kotlin/fr/azur/tcoww/commands/ReloadCommands.kt +++ b/src/main/kotlin/fr/azur/tcoww/commands/ReloadCommands.kt @@ -1,18 +1,21 @@ package fr.azur.tcoww.commands import com.mojang.brigadier.Command -import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.tree.LiteralCommandNode import io.papermc.paper.command.brigadier.CommandSourceStack import io.papermc.paper.command.brigadier.Commands import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import org.bukkit.entity.Player -class ReloadCommands { - val root: LiteralArgumentBuilder = Commands.literal("reloadcommands").executes { ctx -> - val sender = ctx.source.sender as? Player - sender?.updateCommands() - sender?.sendMessage(Component.text("Commands rechargés !").color(NamedTextColor.GOLD)) - Command.SINGLE_SUCCESS - } -} \ No newline at end of file +object ReloadCommands { + val root: LiteralCommandNode = + Commands + .literal("reload-commands") + .executes { ctx -> + val sender = ctx.source.sender as? Player + sender?.updateCommands() + sender?.sendMessage(Component.text("Commands rechargés !", NamedTextColor.GOLD)) + Command.SINGLE_SUCCESS + }.build() +} diff --git a/src/main/kotlin/fr/azur/tcoww/commands/TimeGest.kt b/src/main/kotlin/fr/azur/tcoww/commands/TimeGest.kt deleted file mode 100644 index 0dd1b52..0000000 --- a/src/main/kotlin/fr/azur/tcoww/commands/TimeGest.kt +++ /dev/null @@ -1,44 +0,0 @@ -package fr.azur.tcoww.commands - -import com.mojang.brigadier.Command -import com.mojang.brigadier.builder.LiteralArgumentBuilder -import fr.azur.tcoww.game.TimeGestion -import io.papermc.paper.command.brigadier.CommandSourceStack -import io.papermc.paper.command.brigadier.Commands -import org.bukkit.Bukkit -import org.bukkit.plugin.Plugin -import org.bukkit.scheduler.BukkitTask - -class TimeGest { - var timeGestion: TimeGestion? = null - var sheduler: BukkitTask? = null - var plugin: Plugin? = null - - private fun kill() { - sheduler?.cancel() - sheduler = null - timeGestion = null - } - - val root: LiteralArgumentBuilder = Commands.literal("timegest") - .requires { sender -> - sender.sender.isOp - }.then( - Commands.literal("start").executes { ctx -> - if (plugin == null) plugin = Bukkit.getPluginManager().getPlugin("tcoww")!! - val executor = ctx.source.executor - if (executor == null) throw Error("No executor !") - if (timeGestion != null || sheduler != null) kill() - timeGestion = TimeGestion(plugin!!, executor.world) - sheduler = Bukkit.getScheduler().runTaskTimer(plugin!!, Runnable { - timeGestion!!.tick() - }, 0L, 1L) - Command.SINGLE_SUCCESS - } - ).then( - Commands.literal("kill").executes { - kill() - Command.SINGLE_SUCCESS - } - ) -} \ No newline at end of file diff --git a/src/main/kotlin/fr/azur/tcoww/commands/Tools.kt b/src/main/kotlin/fr/azur/tcoww/commands/Tools.kt index 26aec08..06670ba 100644 --- a/src/main/kotlin/fr/azur/tcoww/commands/Tools.kt +++ b/src/main/kotlin/fr/azur/tcoww/commands/Tools.kt @@ -3,7 +3,7 @@ package fr.azur.tcoww.commands import com.mojang.brigadier.Command import com.mojang.brigadier.arguments.IntegerArgumentType import com.mojang.brigadier.arguments.StringArgumentType -import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.tree.LiteralCommandNode import fr.azur.tcoww.Tcoww import fr.azur.tcoww.items.CustomItems import io.papermc.paper.command.brigadier.CommandSourceStack @@ -16,131 +16,139 @@ import org.bukkit.Bukkit import org.bukkit.Location import org.bukkit.entity.Player -class Tools { - val root: LiteralArgumentBuilder = Commands.literal("tools") - .requires { sender -> - sender.sender.isOp - }.then( - Commands.literal("location") - .then( - Commands.literal("bed").executes { ctx -> - val player = ctx.source.executor as Player - player.inventory.addItem(CustomItems.BedLocTool.item) - Command.SINGLE_SUCCESS - }.then( - Commands.literal("get").executes { ctx -> - ctx.source.sender.sendMessage(sendBed()) - Command.SINGLE_SUCCESS - } - ).then( - Commands.literal("remove").then( - Commands.argument("index", IntegerArgumentType.integer(0)) - .executes { ctx -> - val plugin = Bukkit.getPluginManager().getPlugin("tcoww") ?: return@executes 0 - val index = IntegerArgumentType.getInteger(ctx, "index") - val list = plugin.config.getMapList("bedLocation") - - plugin.config.set("bedLocation", list.minus(list[index])) - plugin.saveConfig() - +object Tools { + val root: LiteralCommandNode = + Commands + .literal("tools") + .requires { sender -> + sender.sender.isOp + }.then( + Commands + .literal("location") + .then( + Commands + .literal("bed") + .executes { ctx -> + val player = ctx.source.executor as Player + player.inventory.addItem(CustomItems.BedLocTool.item) + Command.SINGLE_SUCCESS + }.then( + Commands.literal("get").executes { ctx -> ctx.source.sender.sendMessage(sendBed()) - Command.SINGLE_SUCCESS - } - )) - ).then( - Commands.literal("spawn").executes { ctx -> - val player = ctx.source.executor as Player - player.inventory.addItem(CustomItems.SpawnLocTool.item) - Command.SINGLE_SUCCESS - } - ).then( - Commands.literal("lobby").executes { ctx -> - val player = ctx.source.executor as Player - player.inventory.addItem(CustomItems.LobbyLocTool.item) - Command.SINGLE_SUCCESS - } - ) - ).then( - Commands.literal("reload").executes { - val plugin = Bukkit.getPluginManager().getPlugin("tcoww") as Tcoww - plugin.reload() - Command.SINGLE_SUCCESS - } - ).then( - Commands.literal("customitem").then( - Commands.argument("item", StringArgumentType.greedyString()) - .suggests { _, builder -> - CustomItems.entries.forEach { - builder.suggest(it.name) - } - builder.buildFuture() - } - .executes { ctx -> - val itemName = StringArgumentType.getString(ctx, "item") - val item = CustomItems.valueOf(itemName).item - val exe = ctx.source.executor - if (exe is Player) { - exe.inventory.addItem(item) - } - Command.SINGLE_SUCCESS - } - ) - ) + }, + ).then( + Commands.literal("remove").then( + Commands + .argument("index", IntegerArgumentType.integer(0)) + .executes { ctx -> + val plugin = Bukkit.getPluginManager().getPlugin("tcoww") ?: return@executes 0 + val index = IntegerArgumentType.getInteger(ctx, "index") + val list = + plugin.config + .getList("bed-locations") + .orEmpty() + .mapNotNull { it as? Location } + + plugin.config.set("bed-locations", list.drop(index)) + plugin.saveConfig() + + ctx.source.sender.sendMessage(sendBed()) + + Command.SINGLE_SUCCESS + }, + ), + ), + ).then( + Commands.literal("spawn").executes { ctx -> + val player = ctx.source.executor as Player + player.inventory.addItem(CustomItems.SpawnLocTool.item) + Command.SINGLE_SUCCESS + }, + ).then( + Commands.literal("lobby").executes { ctx -> + val player = ctx.source.executor as Player + player.inventory.addItem(CustomItems.LobbyLocTool.item) + Command.SINGLE_SUCCESS + }, + ), + ).then( + Commands.literal("reload").executes { + val plugin = Bukkit.getPluginManager().getPlugin("tcoww") as Tcoww + plugin.reload() + Command.SINGLE_SUCCESS + }, + ).then( + Commands.literal("customitem").then( + Commands + .argument("item", StringArgumentType.greedyString()) + .suggests { _, builder -> + CustomItems.entries.forEach { + builder.suggest(it.name) + } + builder.buildFuture() + }.executes { ctx -> + val itemName = StringArgumentType.getString(ctx, "item") + val item = CustomItems.valueOf(itemName).item + val exe = ctx.source.executor + if (exe is Player) { + exe.inventory.addItem(item) + } + Command.SINGLE_SUCCESS + }, + ), + ).build() fun sendBed(): Component { val plugin = Bukkit.getPluginManager().getPlugin("tcoww") ?: return Component.empty() - val bedlist = plugin.config.getMapList("bedLocation") - val bedLocationComponent = bedlist.map { - if (it as? Map != null) { - val loc = Location.deserialize(it as Map) - Component.text("[${loc.x}, ${loc.y}, ${loc.z}] ") - .color(NamedTextColor.LIGHT_PURPLE) - .append( - Component.text("teleport") - .clickEvent( - ClickEvent.runCommand("/minecraft:tp ${loc.x.toInt()} ${loc.y.toInt()} ${loc.z.toInt()}") - ) - .color(NamedTextColor.LIGHT_PURPLE) - .decorate(TextDecoration.UNDERLINED) - ) - .appendSpace() - .append( - Component.text("remove") - .clickEvent( - ClickEvent.runCommand( - "/tcoww:tools location bed remove ${ - bedlist.indexOf( - it - ) - }" - ) - ) - .color(NamedTextColor.LIGHT_PURPLE) - .decorate(TextDecoration.UNDERLINED) - ) - .appendNewline() - } else Component.text("[unkown location] ") - .color(NamedTextColor.LIGHT_PURPLE) - .append( - Component.text("remove") - .clickEvent( - ClickEvent.runCommand( - "/tcoww:tools location bed remove ${ - bedlist.indexOf( - it - ) - }" - ) - ) + val bedList = + plugin.config + .getList("bed-locations") + .orEmpty() + val bedLocationComponent = + bedList.mapIndexed { index, element -> + if (element is Location) { + Component + .text("[${element.x}, ${element.y}, ${element.z}] ") .color(NamedTextColor.LIGHT_PURPLE) - .decorate(TextDecoration.UNDERLINED) - ) - .appendNewline() - } - return Component.text("Current bed locations :") + .append( + Component + .text("teleport") + .clickEvent( + ClickEvent.runCommand("/minecraft:tp ${element.x} ${element.y} ${element.z}"), + ).color(NamedTextColor.LIGHT_PURPLE) + .decorate(TextDecoration.UNDERLINED), + ).appendSpace() + .append( + Component + .text("remove") + .clickEvent( + ClickEvent.runCommand( + "/tcoww:tools location bed remove $index", + ), + ).color(NamedTextColor.LIGHT_PURPLE) + .decorate(TextDecoration.UNDERLINED), + ).appendNewline() + } else { + Component + .text("[unkown location] ") + .color(NamedTextColor.LIGHT_PURPLE) + .append( + Component + .text("remove") + .clickEvent( + ClickEvent.runCommand( + "/tcoww:tools location bed remove $index", + ), + ).color(NamedTextColor.LIGHT_PURPLE) + .decorate(TextDecoration.UNDERLINED), + ).appendNewline() + } + } + return Component + .text("Current bed locations :") .color(NamedTextColor.DARK_PURPLE) .appendNewline() .append(bedLocationComponent) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/fr/azur/tcoww/commands/Vote.kt b/src/main/kotlin/fr/azur/tcoww/commands/Vote.kt index 730e2da..9c707c2 100644 --- a/src/main/kotlin/fr/azur/tcoww/commands/Vote.kt +++ b/src/main/kotlin/fr/azur/tcoww/commands/Vote.kt @@ -1,32 +1,53 @@ package fr.azur.tcoww.commands import com.mojang.brigadier.Command -import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.tree.LiteralCommandNode import fr.azur.tcoww.game.Game -import fr.azur.tcoww.game.Phase -import fr.azur.tcoww.utils.Stockage +import fr.azur.tcoww.game.NightLightCycle +import fr.azur.tcoww.ui.PlayerSelectMenu import io.papermc.paper.command.brigadier.CommandSourceStack import io.papermc.paper.command.brigadier.Commands import io.papermc.paper.command.brigadier.argument.ArgumentTypes import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver import org.bukkit.entity.Player +import java.util.UUID -class Vote { - val root: LiteralArgumentBuilder = Commands.literal("vote").then( - Commands.argument("target", ArgumentTypes.player()) - .requires { ctx -> - Game.current?.timeGestion?.phase == Phase.VOTE && Game.current!!.playersMutable.contains(ctx.sender) - }.suggests { ctx, builder -> - Game.current?.playersMutable?.forEach { player -> builder.suggest(player.name) } - builder.buildFuture() - }.executes { ctx -> - val targetResolver = ctx.getArgument("target", PlayerSelectorArgumentResolver::class.java) - val target = targetResolver.resolve(ctx.source).first() +object Vote { + var vote = mutableMapOf() + + val root: LiteralCommandNode = + Commands + .literal("vote") + .then( + Commands + .argument("target", ArgumentTypes.player()) + .requires { ctx -> + Game.current?.timeGestion?.phase == NightLightCycle.Phase.VOTE && + Game.current!!.remainingPlayer.contains(ctx.sender) + }.suggests { _, builder -> + Game.current?.remainingPlayer?.forEach { player -> builder.suggest(player.name) } + builder.buildFuture() + }.executes { ctx -> + val targetResolver = ctx.getArgument("target", PlayerSelectorArgumentResolver::class.java) + val target = targetResolver.resolve(ctx.source).first() + val player = (ctx.source.executor ?: ctx.source.sender as Player) as Player + if (Game.current?.remainingPlayer?.contains(target) ?: false) { + vote[player.uniqueId] = target.uniqueId + } + Command.SINGLE_SUCCESS + }, + ).executes { ctx -> + val current = Game.current ?: return@executes Command.SINGLE_SUCCESS val player = (ctx.source.executor ?: ctx.source.sender as Player) as Player - if (Game.current?.playersMutable?.contains(target) ?: false) { - Stockage.vote[player.uniqueId] = target.uniqueId + + val menu = PlayerSelectMenu(current.remainingPlayer) + player.openInventory(menu.inventory) + + menu.future.whenComplete { selectedPlayer, _ -> + val target = selectedPlayer ?: return@whenComplete + vote[player.uniqueId] = target.uniqueId } + Command.SINGLE_SUCCESS - } - ) -} \ No newline at end of file + }.build() +} diff --git a/src/main/kotlin/fr/azur/tcoww/events/GameEvent.kt b/src/main/kotlin/fr/azur/tcoww/events/GameEvent.kt deleted file mode 100644 index 968b432..0000000 --- a/src/main/kotlin/fr/azur/tcoww/events/GameEvent.kt +++ /dev/null @@ -1,421 +0,0 @@ -package fr.azur.tcoww.events - -import fr.azur.tcoww.game.Game -import fr.azur.tcoww.game.Phase -import fr.azur.tcoww.items.CustomItems -import fr.azur.tcoww.roles.Child -import fr.azur.tcoww.roles.Role -import fr.azur.tcoww.roles.Witch -import fr.azur.tcoww.utils.BedGestion -import fr.azur.tcoww.utils.Skin -import fr.azur.tcoww.utils.Stockage -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.event.ClickEvent -import net.kyori.adventure.text.format.NamedTextColor -import net.kyori.adventure.text.format.TextDecoration -import net.kyori.adventure.title.Title -import org.bukkit.* -import org.bukkit.attribute.Attribute -import org.bukkit.attribute.AttributeModifier -import org.bukkit.entity.EntityType -import org.bukkit.entity.ItemDisplay -import org.bukkit.entity.Player -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority -import org.bukkit.event.Listener -import org.bukkit.event.entity.EntityDamageByEntityEvent -import org.bukkit.event.entity.PlayerDeathEvent -import org.bukkit.event.inventory.InventoryMoveItemEvent -import org.bukkit.event.player.* -import org.bukkit.inventory.ItemStack -import org.bukkit.inventory.meta.SkullMeta -import org.bukkit.persistence.PersistentDataType -import org.bukkit.plugin.Plugin -import org.bukkit.potion.PotionEffect -import org.bukkit.potion.PotionEffectType -import java.time.Duration - -class GameEvent(val plugin: Plugin, val skinUtils: Skin) : Listener { - @EventHandler - fun phaseChange(event: TimePhaseChangeEvent) { - Game.current?.playersMutable?.forEach { it.updateCommands() } - when (event.newPhase) { - Phase.DAY -> { - event.world.players.forEach { player -> - player.sendMessage(Component.text("Le jour se lève.").color(NamedTextColor.GOLD)) - player.clearActivePotionEffects() - player.persistentDataContainer.set( - NamespacedKey("tcoww", "insomie"), - PersistentDataType.BOOLEAN, - false - ) - if (player.role?.lg == true) { - player.inventory.forEach { - if (it != null && it.persistentDataContainer.get( - NamespacedKey("tcoww", "power"), - PersistentDataType.INTEGER - ) == 3 - ) { - player.inventory.remove(it) - } - - if (player.isTransformed()) { - player.tfHuman() - } - } - } - } - } - - Phase.VOTE -> { - event.world.players.forEach { player -> - player.sendMessage( - Component.text("Le jour se couche, ce soir un vote est organisé.") - .color(NamedTextColor.DARK_AQUA) - .appendNewline() - .append( - Component.text("Faite /vote pour voter.") - .color(NamedTextColor.AQUA) - ) - ) - } - } - - Phase.NIGHT -> { - if (Stockage.vote.isNotEmpty()) { - val voteMap = Stockage.vote.values.groupingBy { it }.eachCount() - val mostVoted = voteMap.maxByOrNull { it.value }?.key - mostVoted?.let { uuid -> - Bukkit.getPlayer(uuid)?.let { votedPlayer -> - votedPlayer.fireTicks = 1200 - Bukkit.getScheduler().runTaskLater(plugin, Runnable { - votedPlayer.health = 0.0 - }, 60) - Game.current?.playersMutable?.forEach { - it.sendMessage( - Component.text("${votedPlayer.name} a reçu le plus de vote.") - .color(NamedTextColor.RED) - ) - } - } - } - Stockage.vote.clear() - } - - Game.current?.wwcankill = true - event.world.players.forEach { player -> - player.sendMessage( - Component.text("La lune se léve et les loups sont de sortie. Vous devriez dormir.") - .color(NamedTextColor.DARK_PURPLE) - ) - - if (player.role?.lg ?: false) { - player.sendMessage( - Component.text("Vous pouvez vous transformer.").color(NamedTextColor.DARK_PURPLE) - ) - player.inventory.addItem(CustomItems.WereWolfTransformItem.item) - } - } - - Bukkit.getScheduler().runTaskLater(plugin, Runnable { - val openBed = plugin.config.getMapList("bedLocation").mapNotNull { - if (it as? Map != null) Location.deserialize(it as Map) else null - }.filter { !BedGestion.isOcupied(it.block) }.toMutableList() - Game.current?.playersMutable?.forEach { player -> - if (!player.isSleeping && !player.persistentDataContainer.getOrDefault( - NamespacedKey("tcoww", "dead"), - PersistentDataType.BOOLEAN, - false - ) && !player.isTransformed() - ) { - val loc = openBed.removeFirst() - player.sleep(loc, true) - - val role = player.role - if (role is Child || role?.lg == true) { - player.sendMessage( - Component.text( - "Tout le monde est couché. Vous pouvez vous lever.", - NamedTextColor.AQUA - ) - ) - } - } - } - }, plugin.config.getLong("playerSleep")) - } - - Phase.CREPUSCULAR -> { - val current = Game.current ?: return - val deadPlayers = current.playersMutable.filter { - it.persistentDataContainer.get(NamespacedKey("tcoww", "dead"), PersistentDataType.BOOLEAN) == true - } - - deadPlayers.forEach { player -> - player.gameMode = GameMode.SPECTATOR - Stockage.backLocation[player.uniqueId]?.let { player.teleport(it) } - player.kill(current) - } - - current.playersMutable.removeAll(deadPlayers) - if (current.gameEnded()) { - current.playersMutable.forEach { - if (it.isTransformed()) it.tfHuman() - } - current.stopGame() - } - } - } - } - - @EventHandler - fun powerItemDrop(event: PlayerDropItemEvent) { - val item = event.itemDrop.itemStack - if (event.player.gameMode != GameMode.CREATIVE && - item.itemMeta.persistentDataContainer.has(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER) - ) { - event.isCancelled = true - } - } - - @EventHandler - fun powerItemTransfer(event: InventoryMoveItemEvent) { - val item = event.item - if (event.source != event.destination && - item.itemMeta.persistentDataContainer.has(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER) - ) { - event.isCancelled = true - } - } - - @EventHandler - fun sleepLeaveEvent(event: PlayerBedLeaveEvent) { - val role = event.player.role - if (Game.current?.timeGestion?.phase == Phase.NIGHT && - role !is Child && role?.lg != true && - !event.player.persistentDataContainer.getOrDefault( - NamespacedKey("tcoww", "insomie"), - PersistentDataType.BOOLEAN, - false - ) - ) { - event.isCancelled = true - } - } - - @EventHandler - fun clickEvent(event: PlayerInteractEvent) { - val item = event.item ?: return - if (item.persistentDataContainer.get(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER) == 3) { - val player = event.player - - player.inventory.remove(item) - - if (player.isTransformed()) { - player.tfHuman() - } else { - player.tfWerewolf() - } - } - } - - @EventHandler - fun onDeath(event: PlayerDeathEvent) { - val current = Game.current ?: return - val player = event.player - if (!current.playersMutable.contains(player)) return - - event.isCancelled = true - - if (current.timeGestion.phase == Phase.NIGHT) { - Stockage.backLocation[player.uniqueId] = player.location - Bukkit.getScheduler().runTaskLater(plugin, Runnable { - player.teleport(plugin.config.getLocation("lobbyLocation")!!) - player.clearActivePotionEffects() - player.fireTicks = 0 - }, 1) - player.isInvulnerable = true - player.persistentDataContainer.set(NamespacedKey("tcoww", "dead"), PersistentDataType.BOOLEAN, true) - player.sendMessage( - Component.text("Vous étes mort... Mais vous pouvez être encore résucité.").color( - NamedTextColor.RED - ) - ) - - current.playersMutable.forEach { p -> - if (p.role is Witch && p.inventory.any { - it != null && it.persistentDataContainer.get( - NamespacedKey("tcoww", "power"), - PersistentDataType.INTEGER - ) == 2 - }) { - p.sendMessage( - Component.text("Cette nuit, ${player.name} est mort dans d'atroces souffrances. Vous avez le pouvoir de le/la sauver.\n") - .color(NamedTextColor.DARK_PURPLE) - .append( - Component.text("Cliquez ici pour le/la ressusciter.") - .color(NamedTextColor.DARK_PURPLE) - .decorate(TextDecoration.UNDERLINED) - .clickEvent(ClickEvent.suggestCommand("/power save ${player.name}")) - ) - ) - } - } - } else { - player.kill(current) - } - } - - @EventHandler - fun onHit(event: EntityDamageByEntityEvent) { - val current = Game.current ?: return - if (current.timeGestion.phase != Phase.NIGHT) return - - val damager = event.damager - val target = event.entity - if (damager is Player && target is Player && - current.playersMutable.contains(damager) && - current.playersMutable.contains(target) && - damager.role?.lg == true && - damager.isTransformed() && - target.role?.lg != true && - current.wwcankill - ) { - current.wwcankill = false - target.health = 0.0 - target.persistentDataContainer.set(NamespacedKey("tcoww", "insomie"), PersistentDataType.BOOLEAN, true) - if (target.isSleeping) target.wakeup(false) - } - } - - @EventHandler( - priority = EventPriority.MONITOR, - ignoreCancelled = true - ) - fun startSleep(event: PlayerBedEnterEvent) { - event.player.addPotionEffect( - PotionEffect( - PotionEffectType.REGENERATION, - PotionEffect.INFINITE_DURATION, - 1, - false, - false - ) - ) - } - - @EventHandler( - priority = EventPriority.MONITOR, - ignoreCancelled = true - ) - fun endSleep(event: PlayerBedLeaveEvent) { - event.player.removePotionEffect(PotionEffectType.REGENERATION) - } - - @EventHandler - fun disconnect(event: PlayerQuitEvent) { - val current = Game.current ?: return - val player = event.player - if (!current.playersMutable.contains(player)) return - Bukkit.getScheduler().runTaskLater(plugin, Runnable { - if (!player.isConnected) { - player.kill(current) - } - }, 2_400) - } - - fun Player.kill(current: Game) { - if (isTransformed()) tfHuman() - val item = ItemStack.of(Material.PLAYER_HEAD) - val skullmeta = item.itemMeta as SkullMeta - skullmeta.owningPlayer = player - item.itemMeta = skullmeta - - val loc = this.location.add(0.0, 1.5, 0.0) - val entity = this.world.spawnEntity(loc, EntityType.ITEM_DISPLAY) as ItemDisplay - entity.setItemStack(item) - Bukkit.getScheduler().runTaskLater( - plugin, - Runnable { - entity.remove() - }, - 2400L - ) - - - this.gameMode = GameMode.SPECTATOR - this.isInvulnerable = false - current.playersMutable.remove(player) - - this.showTitle( - Title.title( - Component.text("Vous êtes mort.").color(NamedTextColor.DARK_RED), - Component.empty(), - Title.Times.times(Duration.ZERO, Duration.ofSeconds(2), Duration.ofMillis(500)) - ) - ) - - if (current.gameEnded()) current.stopGame() - } - - fun Player.tfWerewolf() { - if (isTransformed()) return - - skinUtils.applyWerewolfFur(this) - persistentDataContainer.set( - NamespacedKey("tcoww", "wwtranform"), - PersistentDataType.BOOLEAN, - true - ) - - val speedatr = getAttribute(Attribute.MOVEMENT_SPEED)!! - val scaleatr = getAttribute(Attribute.SCALE)!! - - speedatr.addModifier( - AttributeModifier( - NamespacedKey("tcoww", "wwtranform"), - 0.05, - AttributeModifier.Operation.ADD_NUMBER - ) - ) - scaleatr.addModifier( - AttributeModifier( - NamespacedKey("tcoww", "wwtranform"), - 0.1, - AttributeModifier.Operation.ADD_NUMBER - ) - ) - } - - fun Player.tfHuman() { - if (!isTransformed()) return - - skinUtils.unApplySkin(this) - persistentDataContainer.set( - NamespacedKey("tcoww", "wwtranform"), - PersistentDataType.BOOLEAN, - false - ) - - val speedatr = getAttribute(Attribute.MOVEMENT_SPEED)!! - val scaleatr = getAttribute(Attribute.SCALE)!! - speedatr.removeModifier( - NamespacedKey("tcoww", "wwtranform") - ) - scaleatr.removeModifier( - NamespacedKey("tcoww", "wwtranform") - ) - - } - - fun Player.isTransformed(): Boolean { - return persistentDataContainer.getOrDefault( - NamespacedKey("tcoww", "wwtranform"), - PersistentDataType.BOOLEAN, - false - ) - } - - val Player.role - get() = Role.getRole(this) -} diff --git a/src/main/kotlin/fr/azur/tcoww/events/GameEvents.kt b/src/main/kotlin/fr/azur/tcoww/events/GameEvents.kt new file mode 100644 index 0000000..b7ea9cd --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/events/GameEvents.kt @@ -0,0 +1,247 @@ +package fr.azur.tcoww.events + +import fr.azur.tcoww.Tcoww +import fr.azur.tcoww.events.PowerEvents.backLocation +import fr.azur.tcoww.game.Game +import fr.azur.tcoww.game.NightLightCycle +import fr.azur.tcoww.roles.Child +import fr.azur.tcoww.roles.Role +import fr.azur.tcoww.roles.Role.Companion.werewolfRole +import fr.azur.tcoww.roles.Witch +import fr.azur.tcoww.utils.DataKeys.Insomnia +import fr.azur.tcoww.utils.DataKeys.PlayerDead +import fr.azur.tcoww.utils.DataKeys.PowerItems +import fr.azur.tcoww.utils.Players +import fr.azur.tcoww.utils.Players.isTransformed +import fr.azur.tcoww.utils.Players.kill +import fr.azur.tcoww.utils.VoiceChatPlugin +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.event.ClickEvent +import net.kyori.adventure.text.format.NamedTextColor +import net.kyori.adventure.text.format.TextDecoration +import org.bukkit.Bukkit +import org.bukkit.GameMode +import org.bukkit.NamespacedKey +import org.bukkit.entity.Mannequin +import org.bukkit.entity.Player +import org.bukkit.event.EventHandler +import org.bukkit.event.EventPriority +import org.bukkit.event.Listener +import org.bukkit.event.entity.EntityDamageByEntityEvent +import org.bukkit.event.entity.PlayerDeathEvent +import org.bukkit.event.player.PlayerBedEnterEvent +import org.bukkit.event.player.PlayerBedLeaveEvent +import org.bukkit.event.player.PlayerInteractEntityEvent +import org.bukkit.inventory.meta.Damageable +import org.bukkit.persistence.PersistentDataType +import org.bukkit.potion.PotionEffect +import org.bukkit.potion.PotionEffectType + +object GameEvents : Listener { + @EventHandler + fun onDeath(event: PlayerDeathEvent) { + val current = Game.current ?: return + val player = event.player + if (!current.remainingPlayer.contains(player)) return + + event.isCancelled = true + + if (current.timeGestion.phase == NightLightCycle.Phase.NIGHT) { + backLocation[player.uniqueId] = player.location + val lobby = Tcoww.config.getLocation("lobby-location") + Bukkit.getScheduler().runTaskLater( + Tcoww, + Runnable { + if (lobby != null) { + player.teleport(lobby) + } else { + player.gameMode = GameMode.SPECTATOR + } + player.clearActivePotionEffects() + player.fireTicks = 0 + }, + 1, + ) + player.isInvulnerable = true + player.persistentDataContainer.set(PlayerDead, PersistentDataType.BOOLEAN, true) + player.sendMessage( + Component.text( + "Vous étes mort... Mais vous pouvez être encore résucité.", + NamedTextColor.RED, + ), + ) + + current.remainingPlayer.forEach { p -> + if (p.werewolfRole is Witch && + p.inventory.any { + it != null && + it.persistentDataContainer.get( + PowerItems, + PersistentDataType.INTEGER, + ) == 2 && + (it.itemMeta as Damageable).damage != 1 + } + ) { + p.sendMessage( + Component + .text( + "Cette nuit, ${player.name} est mort dans d'atroces souffrances. Vous avez le pouvoir de le/la sauver.\n", + NamedTextColor.DARK_PURPLE, + ).append( + Component + .text("Cliquez ici pour le/la ressusciter.", NamedTextColor.DARK_PURPLE) + .decorate(TextDecoration.UNDERLINED) + .clickEvent( + ClickEvent.callback { + val item = + p.inventory.find { + it != null && + it.persistentDataContainer.get( + PowerItems, + PersistentDataType.INTEGER, + ) == 2 && + (it.itemMeta as Damageable).damage != 1 + } + + if (player.persistentDataContainer.get( + PlayerDead, + PersistentDataType.BOOLEAN, + ) == true + ) { + return@callback + } + if (item == null) return@callback + + (item.itemMeta as Damageable).damage = 1 + + player.persistentDataContainer.set( + NamespacedKey("tcoww", "dead"), + PersistentDataType.BOOLEAN, + false, + ) + backLocation[player.uniqueId]?.let { player.teleport(it) } + player.isInvulnerable = false + player.sendMessage( + Component.text("Vous avez été résucité.", NamedTextColor.AQUA), + ) + player.sendMessage( + Component + .text("Vous avez résuciter ") + .color(NamedTextColor.AQUA) + .append(player.displayName()), + ) + }, + ), + ), + ) + } + } + } else { + player.kill() + } + } + + @EventHandler + fun onHit(event: EntityDamageByEntityEvent) { + val current = Game.current ?: return + if (current.timeGestion.phase != NightLightCycle.Phase.NIGHT) return + + val damager = event.damager + val target = event.entity + if (damager is Player && + target is Player && + current.remainingPlayer.contains(damager) && + current.remainingPlayer.contains(target) && + damager.werewolfRole.team == Role.Team.LG && + damager.isTransformed() && + target.werewolfRole.team != Role.Team.LG + ) { + target.health = 0.0 + target.persistentDataContainer.set(Insomnia, PersistentDataType.BOOLEAN, true) + if (target.isSleeping) target.wakeup(false) + } + } + + @EventHandler + fun sleepLeaveEvent(event: PlayerBedLeaveEvent) { + val role = event.player.werewolfRole + if (Game.current?.timeGestion?.phase == NightLightCycle.Phase.NIGHT && + role !is Child && + role.team != Role.Team.LG && + !event.player.persistentDataContainer.getOrDefault( + Insomnia, + PersistentDataType.BOOLEAN, + false, + ) + ) { + event.isCancelled = true + } + } + + @EventHandler( + priority = EventPriority.MONITOR, + ignoreCancelled = true, + ) + fun startSleep(event: PlayerBedEnterEvent) { + if (event.player.werewolfRole.team == Role.Team.LG) { + VoiceChatPlugin.addWerewolf(event.player) + } else { + VoiceChatPlugin.createSoloGroup(event.player) + } + event.player.addPotionEffect( + PotionEffect( + PotionEffectType.REGENERATION, + PotionEffect.INFINITE_DURATION, + 1, + false, + false, + ), + ) + event.player.addPotionEffect( + PotionEffect( + PotionEffectType.BLINDNESS, + PotionEffect.INFINITE_DURATION, + 1, + false, + false, + ), + ) + } + + @EventHandler( + priority = EventPriority.MONITOR, + ) + fun endSleep(event: PlayerBedLeaveEvent) { + event.player.removePotionEffect(PotionEffectType.REGENERATION) + event.player.removePotionEffect(PotionEffectType.BLINDNESS) + } + + @EventHandler + fun clickOnCorpse(event: PlayerInteractEntityEvent) { + val corpse = event.rightClicked + if (corpse is Mannequin && + corpse.persistentDataContainer.getOrDefault(Players.corpseKey, PersistentDataType.BOOLEAN, false) + ) { + val deadPlayer = Bukkit.getPlayer(corpse.profile.uuid()!!)!! + val playerRole = + Role.registerRoles.getValue( + NamespacedKey.fromString( + corpse.persistentDataContainer.get( + Players.corpseRoleKey, + PersistentDataType.STRING, + )!!, + )!!, + ) + event.player.sendMessage { + Component + .text("Ceci est le cadavre de ", NamedTextColor.DARK_RED) + .append(deadPlayer.displayName()) + .append(Component.text(".", NamedTextColor.DARK_RED)) + .appendNewline() + .append(Component.text("Il était ", NamedTextColor.DARK_RED)) + .append(playerRole.displayName) + .append(Component.text(".", NamedTextColor.DARK_RED)) + } + } + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/events/PhaseEvents.kt b/src/main/kotlin/fr/azur/tcoww/events/PhaseEvents.kt new file mode 100644 index 0000000..958ad0b --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/events/PhaseEvents.kt @@ -0,0 +1,178 @@ +package fr.azur.tcoww.events + +import fr.azur.tcoww.Tcoww +import fr.azur.tcoww.commands.Vote +import fr.azur.tcoww.game.Game +import fr.azur.tcoww.game.NightLightCycle +import fr.azur.tcoww.roles.Child +import fr.azur.tcoww.roles.Role +import fr.azur.tcoww.roles.Role.Companion.werewolfRole +import fr.azur.tcoww.utils.BedGestion.isOccupied +import fr.azur.tcoww.utils.DataKeys.Insomnia +import fr.azur.tcoww.utils.DataKeys.PlayerDead +import fr.azur.tcoww.utils.DataKeys.PowerItems +import fr.azur.tcoww.utils.Players.isTransformed +import fr.azur.tcoww.utils.Players.kill +import fr.azur.tcoww.utils.Players.tfHuman +import fr.azur.tcoww.utils.VoiceChatPlugin +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.Bukkit +import org.bukkit.GameMode +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.persistence.PersistentDataType + +object PhaseEvents : Listener { + @EventHandler + fun phaseChange(event: NightLightCycle.NightLightCyclePhaseChangeEvent) { + val current = Game.current ?: return + current.remainingPlayer.forEach { it.updateCommands() } + when (event.newPhase) { + NightLightCycle.Phase.DAY -> { + event.world.players.forEach { player -> + VoiceChatPlugin.degroupPlayer(player) + player.sendMessage(Component.text("Le jour se lève.", NamedTextColor.GOLD)) + player.clearActivePotionEffects() + player.persistentDataContainer.set( + Insomnia, + PersistentDataType.BOOLEAN, + false, + ) + if (player.werewolfRole.team == Role.Team.LG) { + player.inventory.forEach { + if (it != null && + it.persistentDataContainer.get( + PowerItems, + PersistentDataType.INTEGER, + ) == 3 + ) { + player.setCooldown(it, ((event.duration.day + event.duration.vote) * 20)) + } + + if (player.isTransformed()) { + player.tfHuman() + } + } + } + } + } + + NightLightCycle.Phase.VOTE -> { + event.world.players.forEach { player -> + player.sendMessage( + Component + .text("Le jour se couche, ce soir un vote est organisé.") + .color(NamedTextColor.DARK_AQUA) + .appendNewline() + .append( + Component + .text("Faite /vote pour voter.") + .color(NamedTextColor.AQUA), + ), + ) + } + } + + NightLightCycle.Phase.NIGHT -> { + if (Vote.vote.isNotEmpty()) { + val voteMap = + Vote.vote.values + .groupingBy { it } + .eachCount() + val mostVoted = voteMap.maxByOrNull { it.value }?.key + mostVoted?.let { uuid -> + Bukkit.getPlayer(uuid)?.let { votedPlayer -> + votedPlayer.fireTicks = 1200 + Bukkit.getScheduler().runTaskLater( + Tcoww, + Runnable { + votedPlayer.health = 0.0 + }, + 60, + ) + current.remainingPlayer.forEach { + it.sendMessage( + Component + .text("${votedPlayer.name} a reçu le plus de vote.") + .color(NamedTextColor.RED), + ) + } + } + } + Vote.vote.clear() + } + + event.world.players.forEach { player -> + player.sendMessage( + Component + .text("La lune se léve et les loups sont de sortie. Vous devriez dormir.") + .color(NamedTextColor.DARK_PURPLE), + ) + + if (player.werewolfRole.team == Role.Team.LG) { + player.sendMessage( + Component.text("Vous pouvez vous transformer.", NamedTextColor.DARK_PURPLE), + ) + } + } + + Bukkit.getScheduler().runTaskLater( + Tcoww, + Runnable { + val openBed = + current.beds + .filter { !it.block.isOccupied() } + .toMutableList() + current.remainingPlayer.forEach { player -> + if (!player.isSleeping && + !player.persistentDataContainer.getOrDefault( + PlayerDead, + PersistentDataType.BOOLEAN, + false, + ) && + !player.isTransformed() + ) { + val loc = openBed.removeFirst() + player.sleep(loc, true) + + val role = player.werewolfRole + if (role is Child || role.team == Role.Team.LG) { + player.sendMessage( + Component.text( + "Tout le monde est couché. Vous pouvez vous lever.", + NamedTextColor.AQUA, + ), + ) + } + } + } + }, + Tcoww.config.getLong("player-sleep"), + ) + } + + NightLightCycle.Phase.CREPUSCULAR -> { + val current = Game.current ?: return + val deadPlayers = + current.remainingPlayer.filter { + it.persistentDataContainer.get(PlayerDead, PersistentDataType.BOOLEAN) == true + } + + deadPlayers.forEach { player -> + player.gameMode = GameMode.SPECTATOR + PowerEvents.backLocation[player.uniqueId]?.let { player.teleport(it) } + player.kill() + } + + current.remainingPlayer.removeAll(deadPlayers) +// if (current.gameEnded()) { +// current.remainingPlayer.forEach { +// if (it.isTransformed()) it.tfHuman() +// } +// current.stopGame() +// } + } + } + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/events/PowerEvents.kt b/src/main/kotlin/fr/azur/tcoww/events/PowerEvents.kt new file mode 100644 index 0000000..c08cb1c --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/events/PowerEvents.kt @@ -0,0 +1,157 @@ +package fr.azur.tcoww.events + +import fr.azur.tcoww.game.Game +import fr.azur.tcoww.roles.Role +import fr.azur.tcoww.ui.PlayerSelectMenu +import fr.azur.tcoww.utils.DataKeys +import fr.azur.tcoww.utils.Players.isTransformed +import fr.azur.tcoww.utils.Players.tfHuman +import fr.azur.tcoww.utils.Players.tfWerewolf +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.event.HoverEvent +import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.GameMode +import org.bukkit.Location +import org.bukkit.NamespacedKey +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.inventory.InventoryMoveItemEvent +import org.bukkit.event.player.PlayerDropItemEvent +import org.bukkit.event.player.PlayerInteractEvent +import org.bukkit.inventory.meta.Damageable +import org.bukkit.persistence.PersistentDataType +import org.bukkit.potion.PotionEffect +import org.bukkit.potion.PotionEffectType +import java.util.UUID + +object PowerEvents : Listener { + var backLocation = mutableMapOf() + + @EventHandler + fun powerItemDrop(event: PlayerDropItemEvent) { + val item = event.itemDrop.itemStack + if (event.player.gameMode != GameMode.CREATIVE && + item.itemMeta.persistentDataContainer.has(DataKeys.PowerItems, PersistentDataType.INTEGER) + ) { + event.isCancelled = true + } + } + + @EventHandler + fun powerItemTransfer(event: InventoryMoveItemEvent) { + val item = event.item + if (event.source != event.destination && + item.itemMeta.persistentDataContainer.has(DataKeys.PowerItems, PersistentDataType.INTEGER) + ) { + event.isCancelled = true + } + } + + @EventHandler + fun clickEvent(event: PlayerInteractEvent) { + val item = event.item ?: return + val player = event.player + if (player.hasCooldown(item)) return + when (item.persistentDataContainer.get(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER)) { + 1 -> { + if ((item.itemMeta as Damageable).damage == 1) return + val current = Game.current ?: return + + val menu = PlayerSelectMenu(current.remainingPlayer) + player.openInventory(menu.inventory) + + menu.future.whenComplete { selectedPlayer, _ -> + val target = selectedPlayer ?: return@whenComplete + (item.itemMeta as Damageable).damage = 1 + target.addPotionEffect(PotionEffect(PotionEffectType.WITHER, 600, 4)) + } + } + + 2 -> { + if ((item.itemMeta as Damageable).damage == 1) return + val current = Game.current ?: return + + val menu = + PlayerSelectMenu( + current.remainingPlayer.filter { + it.persistentDataContainer.get( + NamespacedKey("tcoww", "dead"), + PersistentDataType.BOOLEAN, + ) == true + }, + ) + + player.openInventory(menu.inventory) + + menu.future.whenComplete { selectedPlayer, _ -> + val target = selectedPlayer ?: return@whenComplete + (item.itemMeta as Damageable).damage = 1 + target.persistentDataContainer.set( + NamespacedKey("tcoww", "dead"), + PersistentDataType.BOOLEAN, + false, + ) + backLocation[target.uniqueId]?.let { target.teleport(it) } + target.isInvulnerable = false + target.sendMessage(Component.text("Vous avez été résucité.", NamedTextColor.AQUA)) + player.sendMessage( + Component + .text("Vous avez résuciter ") + .color(NamedTextColor.AQUA) + .append(player.displayName()), + ) + } + } + + 3 -> { + player.setCooldown(item, 600) + + if (player.isTransformed()) { + player.tfHuman() + } else { + player.tfWerewolf() + } + } + + 4 -> { + val current = Game.current ?: return + val timeGestion = current.timeGestion + + val menu = PlayerSelectMenu(current.remainingPlayer) + player.openInventory(menu.inventory) + + menu.future.whenComplete { selectedPlayer, _ -> + val target = selectedPlayer ?: return@whenComplete + + val cooldown = + ( + ( + timeGestion.duration.day + timeGestion.duration.vote + timeGestion.duration.night + + timeGestion.duration.crepuscular - + 30 + ) * + 2 + ) * + 20 + + player.setCooldown(item, cooldown) + + val targetRole = Role.getRole(target) + + player.sendMessage( + target + .displayName() + .append(Component.text(" est ")) + .append( + targetRole?.displayName ?: Component.text("Inconnu").hoverEvent( + HoverEvent.showText( + targetRole?.lineDescription ?: Component.empty(), + ), + ), + ), + ) + } + } + } + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/events/TimePhaseChangeEvent.kt b/src/main/kotlin/fr/azur/tcoww/events/TimePhaseChangeEvent.kt deleted file mode 100644 index 18ba92a..0000000 --- a/src/main/kotlin/fr/azur/tcoww/events/TimePhaseChangeEvent.kt +++ /dev/null @@ -1,20 +0,0 @@ -package fr.azur.tcoww.events - -import fr.azur.tcoww.game.Phase -import org.bukkit.World -import org.bukkit.event.Event -import org.bukkit.event.HandlerList - -class TimePhaseChangeEvent( - val world: World, - val newPhase: Phase -) : Event() { - override fun getHandlers(): HandlerList { - return handlerList - } - - companion object { - @JvmStatic - val handlerList: HandlerList = HandlerList() - } -} \ No newline at end of file diff --git a/src/main/kotlin/fr/azur/tcoww/events/ToolsEvents.kt b/src/main/kotlin/fr/azur/tcoww/events/ToolsEvents.kt index ab4d353..c744a58 100644 --- a/src/main/kotlin/fr/azur/tcoww/events/ToolsEvents.kt +++ b/src/main/kotlin/fr/azur/tcoww/events/ToolsEvents.kt @@ -1,47 +1,56 @@ package fr.azur.tcoww.events -import fr.azur.tcoww.utils.BedGestion +import fr.azur.tcoww.Tcoww +import fr.azur.tcoww.utils.BedGestion.getHeadBed +import fr.azur.tcoww.utils.BedGestion.isBed +import fr.azur.tcoww.utils.DataKeys import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor -import org.bukkit.NamespacedKey +import org.bukkit.Location import org.bukkit.event.EventHandler import org.bukkit.event.Listener import org.bukkit.event.player.PlayerInteractEvent import org.bukkit.persistence.PersistentDataType -import org.bukkit.plugin.java.JavaPlugin -class ToolsEvents(val plugin: JavaPlugin) : Listener { +object ToolsEvents : Listener { @EventHandler fun clickEvent(event: PlayerInteractEvent) { val tool = event.player.inventory.itemInMainHand - if (!tool.persistentDataContainer.has(NamespacedKey("tcoww", "tools"))) return + if (!tool.persistentDataContainer.has(DataKeys.ToolsItems) || event.player.hasCooldown(tool)) return - when (tool.persistentDataContainer.get(NamespacedKey("tcoww", "tools"), PersistentDataType.INTEGER)) { + event.player.setCooldown(tool, 20) + + when (tool.persistentDataContainer.get(DataKeys.ToolsItems, PersistentDataType.INTEGER)) { 1 -> { event.isCancelled = true - val interactloc = event.interactionPoint - if (interactloc != null) { - if (BedGestion.isBed(interactloc.block)) { - val list = plugin.config.getMapList("bedLocation") + val interactLoc = event.interactionPoint + if (interactLoc != null) { + if (interactLoc.block.isBed()) { + val list = + Tcoww.config + .getList("bed-locations") + .orEmpty() + .mapNotNull { it as? Location } + .toMutableList() - val block = BedGestion.getHeadBed(interactloc.block) + val block = interactLoc.block.getHeadBed() - if (!list.contains(block.location.serialize())) { - list.add(block.location.serialize()) - plugin.config.set("bedLocation", list) - plugin.saveConfig() + if (!list.contains(block.location)) { + list.add(block.location) + Tcoww.config.set("bed-locations", list) + Tcoww.saveConfig() event.player.sendMessage( - Component.text("Bed location add.").color(NamedTextColor.LIGHT_PURPLE) + Component.text("Bed location add.", NamedTextColor.LIGHT_PURPLE), ) } else { event.player.sendMessage( - Component.text("Bed location already exists.").color(NamedTextColor.DARK_RED) + Component.text("Bed location already exists.", NamedTextColor.DARK_RED), ) } } else { event.player.sendMessage( - Component.text("It's not a bed...").color(NamedTextColor.DARK_RED) + Component.text("It's not a bed...", NamedTextColor.DARK_RED), ) } } @@ -49,34 +58,29 @@ class ToolsEvents(val plugin: JavaPlugin) : Listener { 2 -> { event.isCancelled = true - val interactloc = event.interactionPoint - if (interactloc != null) { - interactloc.x = interactloc.blockX.toDouble() - interactloc.y = interactloc.blockY.toDouble() + 1 - interactloc.z = interactloc.blockZ.toDouble() - plugin.config.set("spawnLocation", interactloc) - plugin.saveConfig() - event.player.sendMessage(Component.text("Spawn location set.").color(NamedTextColor.LIGHT_PURPLE)) + val interactLoc = event.interactionPoint + if (interactLoc != null) { + interactLoc.x = interactLoc.blockX.toDouble() + interactLoc.y = interactLoc.blockY.toDouble() + 1 + interactLoc.z = interactLoc.blockZ.toDouble() + Tcoww.config.set("spawn-location", interactLoc) + Tcoww.saveConfig() + event.player.sendMessage(Component.text("Spawn location set.", NamedTextColor.LIGHT_PURPLE)) } } 3 -> { event.isCancelled = true - val interactloc = event.interactionPoint - if (interactloc != null) { - interactloc.x = interactloc.blockX.toDouble() - interactloc.y = interactloc.blockY.toDouble() + 1 - interactloc.z = interactloc.blockZ.toDouble() - plugin.config.set("lobbyLocation", interactloc) - plugin.saveConfig() - event.player.sendMessage(Component.text("Lobby location set.").color(NamedTextColor.LIGHT_PURPLE)) + val interactLoc = event.interactionPoint + if (interactLoc != null) { + interactLoc.x = interactLoc.blockX.toDouble() + interactLoc.y = interactLoc.blockY.toDouble() + 1 + interactLoc.z = interactLoc.blockZ.toDouble() + Tcoww.config.set("lobby-location", interactLoc) + Tcoww.saveConfig() + event.player.sendMessage(Component.text("Lobby location set.", NamedTextColor.LIGHT_PURPLE)) } } } } - -// @EventHandler -// fun reloadAfterWorld(worldInitEvent: WorldInitEvent) { -// -// } -} \ No newline at end of file +} diff --git a/src/main/kotlin/fr/azur/tcoww/events/UIEvents.kt b/src/main/kotlin/fr/azur/tcoww/events/UIEvents.kt new file mode 100644 index 0000000..1eb50c8 --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/events/UIEvents.kt @@ -0,0 +1,27 @@ +package fr.azur.tcoww.events + +import fr.azur.tcoww.ui.CustomUI +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.event.inventory.InventoryCloseEvent + +object UIEvents : Listener { + @EventHandler + fun onInventoryClick(event: InventoryClickEvent) { + val inventory = event.inventory + val holder = inventory.getHolder(false) + if (holder is CustomUI) { + holder.onClick(event) + } + } + + @EventHandler + fun onInventoryClick(event: InventoryCloseEvent) { + val inventory = event.inventory + val holder = inventory.getHolder(false) + if (holder is CustomUI) { + holder.onClose(event) + } + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/game/Game.kt b/src/main/kotlin/fr/azur/tcoww/game/Game.kt index 01a5ac4..d8ab837 100644 --- a/src/main/kotlin/fr/azur/tcoww/game/Game.kt +++ b/src/main/kotlin/fr/azur/tcoww/game/Game.kt @@ -1,35 +1,42 @@ package fr.azur.tcoww.game +import fr.azur.tcoww.Tcoww import fr.azur.tcoww.roles.Role -import fr.azur.tcoww.roles.Villager -import fr.azur.tcoww.roles.Werewolf +import fr.azur.tcoww.roles.Role.Companion.werewolfRole +import fr.azur.tcoww.utils.Players.tfHuman import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import org.bukkit.Bukkit import org.bukkit.GameMode +import org.bukkit.Location import org.bukkit.NamespacedKey import org.bukkit.World import org.bukkit.entity.Player -import org.bukkit.persistence.PersistentDataType import org.bukkit.plugin.Plugin import org.bukkit.potion.PotionEffect import org.bukkit.potion.PotionEffectType -import org.bukkit.scheduler.BukkitTask -import kotlin.math.ceil -class Game(var plugin: Plugin, val world: World, val players: Iterable, var roles: Iterable) { - val werewolfPercentage: Float = plugin.config.getInt("wwcount").toFloat() - val timeGestion: TimeGestion - val playersMutable = players.toMutableList() - val timeGestShedule: BukkitTask - var wwcankill = false +class Game( + var plugin: Plugin, + val world: World, + val players: Iterable, + var roles: Map, +) { + val timeGestion: NightLightCycle + val remainingPlayer = players.toMutableList() + val beds = + Tcoww.config + .getList("bed-locations") + .orEmpty() + .mapNotNull { it as? Location } init { players.forEach { player -> - player.persistentDataContainer.set(NamespacedKey("tcoww", "dead"), PersistentDataType.BOOLEAN, false) - player.persistentDataContainer.set(NamespacedKey("tcoww", "wwtranform"), PersistentDataType.BOOLEAN, false) - player.teleport(plugin.config.getLocation("spawnLocation")!!) + player.tfHuman() + val spawnLoc = plugin.config.getLocation("spawn-location") + if (spawnLoc != null) player.teleport(spawnLoc) player.inventory.clear() + player.gameMode = GameMode.ADVENTURE player.health = 20.0 player.addPotionEffect( PotionEffect( @@ -37,47 +44,27 @@ class Game(var plugin: Plugin, val world: World, val players: Iterable, PotionEffect.INFINITE_DURATION, 1, false, - false - ) + false, + ), ) } assignRoles() - timeGestion = TimeGestion(plugin, world) - - timeGestShedule = Bukkit.getScheduler().runTaskTimer(plugin, Runnable { - timeGestion.tick() - }, 0L, 1L) + timeGestion = NightLightCycle(plugin, world) current = this } - fun getWerewolfInt(): Int { - val playerCount = players.count() - return ceil(playerCount * (werewolfPercentage / 100f)).toInt() - } - private fun assignRoles() { - val playerList = players.shuffled().toMutableList() - - val werewolfCount = getWerewolfInt() - val specialRolesCount = roles.count() - - if (werewolfCount + specialRolesCount > playerList.size) { - throw IllegalArgumentException("Not enough players for the given number of werewolves and special roles.") - } - - repeat(werewolfCount) { i -> - Role.setRole(playerList[i], Werewolf()) - } - - roles.forEachIndexed { idx, role -> - Role.setRole(playerList[werewolfCount + idx], role) - } - - for (i in werewolfCount + specialRolesCount until playerList.size) { - Role.setRole(playerList[i], Villager()) + val playersShuffled = players.shuffled() + var playerIndex = 0 + roles.forEach { + val role = Role.registerRoles.getValue(it.key) + for (i in 0.., var current: Game? = null } - fun gameEnded(): Boolean { - var hasWerewolf = false - var hasVillager = false - - for (player in playersMutable) { - val isWerewolf = Role.getRole(player)?.lg ?: false - if (isWerewolf) hasWerewolf = true else hasVillager = true - if (hasWerewolf && hasVillager) return false - } - - return true + fun checkGameEnd(): Boolean { + val team = players.map { player -> player.werewolfRole.team }.toSet() + return team.count() <= 1 } fun stopGame(withoutResult: Boolean = false) { current ?: return current = null - timeGestShedule.cancel() + timeGestion.stop() world.time = 18000 players.forEach { player -> player.gameMode = GameMode.SPECTATOR player.sendMessage( - Component.text("La partie est terminée !", NamedTextColor.DARK_GREEN) + Component + .text("La partie est terminée !", NamedTextColor.DARK_GREEN) .appendNewline() - .append { - if (withoutResult) - Component.empty() - else { - val villageHasWolf = playersMutable.any { - Role.getRole(it)?.lg ?: false - } - if (villageHasWolf) { - Component.text( - "Les loups-garous ont finalement dévoré le village.", - NamedTextColor.DARK_RED - ) - } else { - Component.text( - "Les villageois ont finalement sauvé le village.", - NamedTextColor.DARK_BLUE + .apply { + if (!withoutResult) return@apply + remainingPlayer.forEachIndexed { index, player -> + append(player.displayName()) + + if (index != remainingPlayer.lastIndex) { + append( + Component.text( + when (index) { + remainingPlayer.lastIndex - 1 -> " et " + else -> ", " + }, + NamedTextColor.DARK_GREEN, + ), ) } + + append(Component.text(" ont gagné !", NamedTextColor.DARK_GREEN)) } - } + }, ) } - Bukkit.getScheduler().runTaskLater(plugin, Runnable { - players.forEach { player -> - player.teleport(plugin.config.getLocation("lobbyLocation")!!) - player.gameMode = GameMode.ADVENTURE - } - }, 200) + val lobbyLoc = plugin.config.getLocation("lobby-location") + Bukkit.getScheduler().runTaskLater( + plugin, + Runnable { + players.forEach { player -> + if (lobbyLoc != null) player.teleport(lobbyLoc) + player.gameMode = GameMode.ADVENTURE + } + }, + 200, + ) } } diff --git a/src/main/kotlin/fr/azur/tcoww/game/NightLightCycle.kt b/src/main/kotlin/fr/azur/tcoww/game/NightLightCycle.kt new file mode 100644 index 0000000..0b75c99 --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/game/NightLightCycle.kt @@ -0,0 +1,127 @@ +package fr.azur.tcoww.game + +import org.bukkit.Bukkit +import org.bukkit.GameRule +import org.bukkit.World +import org.bukkit.event.Event +import org.bukkit.event.HandlerList +import org.bukkit.plugin.Plugin +import org.bukkit.scheduler.BukkitTask + +class NightLightCycle( + plugin: Plugin, + val world: World, +) { + enum class Phase { + DAY, + VOTE, + NIGHT, + CREPUSCULAR, + } + + class NightLightCyclePhaseChangeEvent( + val world: World, + val newPhase: Phase, + val duration: Duration, + ) : Event() { + override fun getHandlers(): HandlerList = handlerList + + companion object { + @JvmStatic + val handlerList: HandlerList = HandlerList() + } + } + + data class Duration( + val day: Int, + val vote: Int, + val night: Int, + val crepuscular: Int, + ) { + companion object { + fun fromPlugin(plugin: Plugin): Duration { + val dayDuration = plugin.config.getInt("duration.day") + val voteDuration = plugin.config.getInt("duration.vote") + val nightDuration = plugin.config.getInt("duration.night") + val crepuscularDuration = plugin.config.getInt("duration.crepuscular") + return Duration(dayDuration, voteDuration, nightDuration, crepuscularDuration) + } + } + } + + var phase: Phase = Phase.DAY + val phases = Phase.entries + val process: BukkitTask + + val duration = Duration.fromPlugin(plugin) + + var targetInstant: Long + var tickOrigin: Int = 0 + var realDifference: Int + var tickDifference: Int + + var dayCount: Int = 0 + + init { + world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false) + realDifference = duration.day * 1000 + targetInstant = System.currentTimeMillis() + realDifference.toLong() + tickDifference = 12_000 + Bukkit.getPluginManager().callEvent(NightLightCyclePhaseChangeEvent(world, phase, duration)) + + process = + Bukkit.getScheduler().runTaskTimer( + plugin, + Runnable { + this.tick() + }, + 0L, + 1L, + ) + } + + fun changePhase(newPhase: Phase) { + when (newPhase) { + Phase.DAY -> { + tickDifference = 12_000 + tickOrigin = 0 + realDifference = duration.day * 1000 + } + + Phase.VOTE -> { + tickDifference = 1_000 + tickOrigin = 12_000 + realDifference = duration.vote * 1000 + } + + Phase.NIGHT -> { + tickDifference = 11_000 + tickOrigin = 13_000 + realDifference = duration.night * 1000 + } + + Phase.CREPUSCULAR -> { + tickDifference = 1_000 + tickOrigin = 23_000 + realDifference = duration.crepuscular * 1000 + } + } + targetInstant = System.currentTimeMillis() + realDifference + phase = newPhase + Bukkit.getPluginManager().callEvent(NightLightCyclePhaseChangeEvent(world, newPhase, duration)) + } + + fun tick() { + if (System.currentTimeMillis() >= targetInstant) { + val phase = phases[(phases.indexOf(phase) + 1) % phases.count()] + if (phase == Phase.DAY) { + dayCount += 1 + } + changePhase(phase) + } + } + + fun stop() { + process.cancel() + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/game/Phase.kt b/src/main/kotlin/fr/azur/tcoww/game/Phase.kt deleted file mode 100644 index 7c067a3..0000000 --- a/src/main/kotlin/fr/azur/tcoww/game/Phase.kt +++ /dev/null @@ -1,8 +0,0 @@ -package fr.azur.tcoww.game - -enum class Phase { - DAY, - VOTE, - NIGHT, - CREPUSCULAR -} \ No newline at end of file diff --git a/src/main/kotlin/fr/azur/tcoww/game/TimeGestion.kt b/src/main/kotlin/fr/azur/tcoww/game/TimeGestion.kt deleted file mode 100644 index 985956d..0000000 --- a/src/main/kotlin/fr/azur/tcoww/game/TimeGestion.kt +++ /dev/null @@ -1,81 +0,0 @@ -package fr.azur.tcoww.game - -import fr.azur.tcoww.events.TimePhaseChangeEvent -import org.bukkit.Bukkit -import org.bukkit.World -import org.bukkit.GameRule -import org.bukkit.plugin.Plugin -import java.util.Calendar - -class TimeGestion(plugin: Plugin, val world: World) { - var calendar: Calendar = Calendar.getInstance() - var targetCalendar: Calendar = calendar.clone() as Calendar - var difference: Long - var differencetick: Int - - val dayDuration: Int = plugin.config.getInt("duration.day") - val voteDuration: Int = plugin.config.getInt("duration.vote") - val nightDuration: Int = plugin.config.getInt("duration.night") - val crepuscularDuration: Int = plugin.config.getInt("duration.crepuscular") - - var phase: Phase = Phase.DAY - var tickcorrecter = 0 - - init { - world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false) - targetCalendar.add(Calendar.SECOND, dayDuration) - difference = targetCalendar.timeInMillis - calendar.timeInMillis - differencetick = 12500 - Bukkit.getPluginManager().callEvent(TimePhaseChangeEvent(world,phase)) - } - - fun changePhase() { - calendar = Calendar.getInstance() - targetCalendar = calendar.clone() as Calendar - - when (phase) { - // vote - Phase.DAY -> { - phase = Phase.VOTE - tickcorrecter = 12_500 - differencetick = 1_500 - targetCalendar.add(Calendar.SECOND, voteDuration) - } - // night - Phase.VOTE -> { - phase = Phase.NIGHT - tickcorrecter = 14_000 - differencetick = 8_500 - targetCalendar.add(Calendar.SECOND, nightDuration) - } - // crepuscular - Phase.NIGHT -> { - phase = Phase.CREPUSCULAR - tickcorrecter = 22_500 - differencetick = 1_500 - targetCalendar.add(Calendar.SECOND, crepuscularDuration) - } - // day - Phase.CREPUSCULAR -> { - phase = Phase.DAY - tickcorrecter = 0 - differencetick = 12_500 - targetCalendar.add(Calendar.SECOND, dayDuration) - } - } - Bukkit.getPluginManager().callEvent(TimePhaseChangeEvent(world,phase)) - - difference = targetCalendar.timeInMillis - calendar.timeInMillis - } - - fun tick() { - if (System.currentTimeMillis() >= targetCalendar.timeInMillis) { - changePhase() - } - - if (difference == 0L) return - - val result = tickcorrecter + ((differencetick.toDouble() * (System.currentTimeMillis() - calendar.timeInMillis)) / difference).toInt() - world.time = result.coerceIn(0, 23999).toLong() - } -} diff --git a/src/main/kotlin/fr/azur/tcoww/items/CustomItems.kt b/src/main/kotlin/fr/azur/tcoww/items/CustomItems.kt index de2fa5e..1728b14 100644 --- a/src/main/kotlin/fr/azur/tcoww/items/CustomItems.kt +++ b/src/main/kotlin/fr/azur/tcoww/items/CustomItems.kt @@ -2,12 +2,12 @@ package fr.azur.tcoww.items import fr.azur.tcoww.game.Game import fr.azur.tcoww.roles.Role +import fr.azur.tcoww.utils.DataKeys import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextDecoration import org.bukkit.Color import org.bukkit.Material -import org.bukkit.NamespacedKey import org.bukkit.enchantments.Enchantment import org.bukkit.entity.Player import org.bukkit.inventory.ItemRarity @@ -19,181 +19,205 @@ import org.bukkit.persistence.PersistentDataType import org.bukkit.potion.PotionEffect import org.bukkit.potion.PotionEffectType -enum class CustomItems(val cache: Boolean, val supplier: () -> ItemStack) { +enum class CustomItems( + val cache: Boolean, + val supplier: () -> ItemStack, +) { WereWolfTransformItem(true, { ItemStack.of(Material.BONE).apply { - itemMeta = itemMeta.apply { - customName(Component.text("Os de transformation").color(NamedTextColor.DARK_RED)) - persistentDataContainer.set( - NamespacedKey("tcoww", "power"), - PersistentDataType.INTEGER, - 3 - ) - lore( - listOf( - Component.text("Clique pour basculer en forme loup-garou.") - .color(NamedTextColor.GOLD) + itemMeta = + itemMeta.apply { + customName(Component.text("Os de transformation", NamedTextColor.DARK_RED)) + persistentDataContainer.set( + DataKeys.PowerItems, + PersistentDataType.INTEGER, + 3, ) - ) - } + lore( + listOf( + Component + .text("Clique pour basculer en forme loup-garou.") + .color(NamedTextColor.GOLD), + ), + ) + } } }), GunBullet(true, { ItemStack(Material.TIPPED_ARROW).apply { - itemMeta = (itemMeta as PotionMeta).apply { - color = Color.ORANGE - displayName(Component.text("Balle de fusil.", NamedTextColor.YELLOW)) - basePotionType = basePotionType.apply { - addCustomEffect(PotionEffect(PotionEffectType.INSTANT_DAMAGE, 20, 99), true) + itemMeta = + (itemMeta as PotionMeta).apply { + color = Color.ORANGE + displayName(Component.text("Balle de fusil.", NamedTextColor.YELLOW)) + basePotionType = + basePotionType.apply { + addCustomEffect(PotionEffect(PotionEffectType.INSTANT_DAMAGE, 20, 99), true) + } } - } } }), BlasTechDL44(true, { ItemStack.of(Material.CROSSBOW).apply { - itemMeta = (itemMeta as CrossbowMeta).apply { - addChargedProjectile(GunBullet.item) - displayName(Component.text("BlasTech DL-44", NamedTextColor.GOLD)) - addEnchant(Enchantment.INFINITY, 1, true) - } - itemMeta = (itemMeta as Damageable).apply { - setMaxDamage(1) - } + itemMeta = + (itemMeta as DamageableCrossbow).apply { + addChargedProjectile(GunBullet.item) + displayName(Component.text("BlasTech DL-44", NamedTextColor.GOLD)) + addEnchant(Enchantment.INFINITY, 1, true) + setMaxDamage(1) + } } }), CrystalBall(true, { ItemStack.of(Material.GLASS).apply { - itemMeta = itemMeta.apply { - customName( - Component.text("Boule de cristal").color(NamedTextColor.AQUA) - ) - persistentDataContainer.set( - NamespacedKey("tcoww", "power"), - PersistentDataType.INTEGER, - 4 - ) - lore(listOf(Component.text("/power view pour l'utiliser.").color(NamedTextColor.GOLD))) - } + itemMeta = + itemMeta.apply { + customName( + Component.text("Boule de cristal", NamedTextColor.AQUA), + ) + persistentDataContainer.set( + DataKeys.PowerItems, + PersistentDataType.INTEGER, + 4, + ) + setMaxStackSize(1) + lore(listOf(Component.text("Click droit pour utiliser.", NamedTextColor.GOLD))) + } } - } - ), + }), DeathPotion(true, { ItemStack.of(Material.POTION).apply { - itemMeta = (itemMeta as PotionMeta).apply { - customName( - Component.text("Potion de poison").color(NamedTextColor.DARK_PURPLE) - ) - persistentDataContainer.set( - NamespacedKey("tcoww", "power"), - PersistentDataType.INTEGER, - 1 - ) - color = Color.BLACK - lore( - listOf( - Component.text("/power kill pour l'utiliser.").color(NamedTextColor.GOLD) + itemMeta = + (itemMeta as DamageablePotion).apply { + setMaxStackSize(1) + setMaxDamage(1) + customName( + Component.text("Potion de poison", NamedTextColor.DARK_PURPLE), ) - ) - } + persistentDataContainer.set( + DataKeys.PowerItems, + PersistentDataType.INTEGER, + 1, + ) + color = Color.BLACK + lore( + listOf( + Component.text("Click droit pour utiliser.", NamedTextColor.GOLD), + ), + ) + } } }), HealPotion(true, { ItemStack.of(Material.POTION).apply { - itemMeta = (itemMeta as PotionMeta).apply { - customName( - Component.text("Potion de vie").color(NamedTextColor.DARK_PURPLE) - ) - persistentDataContainer.set( - NamespacedKey("tcoww", "power"), - PersistentDataType.INTEGER, - 2 - ) - color = Color.RED - lore(listOf(Component.text("/power save pour l'utiliser.").color(NamedTextColor.GOLD))) - } + itemMeta = + (itemMeta as DamageablePotion).apply { + setMaxStackSize(1) + setMaxDamage(1) + customName( + Component.text("Potion de vie", NamedTextColor.DARK_PURPLE), + ) + persistentDataContainer.set( + DataKeys.PowerItems, + PersistentDataType.INTEGER, + 2, + ) + color = Color.RED + lore(listOf(Component.text("Click droit pour utiliser.", NamedTextColor.GOLD))) + } } }), SpawnLocTool(true, { ItemStack.of(Material.SUGAR_CANE).apply { - itemMeta = itemMeta.apply { - setRarity(ItemRarity.EPIC) - persistentDataContainer.set( - NamespacedKey("tcoww", "tools"), - PersistentDataType.INTEGER, - 2 - ) - lore(listOf(Component.text("Spawn location tool").color(NamedTextColor.GOLD))) - } + itemMeta = + itemMeta.apply { + setRarity(ItemRarity.EPIC) + persistentDataContainer.set( + DataKeys.ToolsItems, + PersistentDataType.INTEGER, + 2, + ) + lore(listOf(Component.text("Spawn location tool", NamedTextColor.GOLD))) + } } }), BedLocTool(true, { ItemStack.of(Material.WOODEN_HOE).apply { - itemMeta = itemMeta.apply { - setRarity(ItemRarity.EPIC) - persistentDataContainer.set( - NamespacedKey("tcoww", "tools"), - PersistentDataType.INTEGER, - 1 - ) - lore(listOf(Component.text("bed location tool").color(NamedTextColor.GOLD))) - } + itemMeta = + itemMeta.apply { + setRarity(ItemRarity.EPIC) + persistentDataContainer.set( + DataKeys.ToolsItems, + PersistentDataType.INTEGER, + 1, + ) + lore(listOf(Component.text("bed location tool", NamedTextColor.GOLD))) + } } }), LobbyLocTool(true, { ItemStack.of(Material.POPPED_CHORUS_FRUIT).apply { - itemMeta = itemMeta.apply { - setRarity(ItemRarity.EPIC) - persistentDataContainer.set( - NamespacedKey("tcoww", "tools"), - PersistentDataType.INTEGER, - 3 - ) - lore(listOf(Component.text("Lobby location tool").color(NamedTextColor.GOLD))) - } + itemMeta = + itemMeta.apply { + setRarity(ItemRarity.EPIC) + persistentDataContainer.set( + DataKeys.ToolsItems, + PersistentDataType.INTEGER, + 3, + ) + lore(listOf(Component.text("Lobby location tool", NamedTextColor.GOLD))) + } } }), ListHint(false, { - val finalLore = buildList { - add( - Component.text("C'est une liste de nom.", NamedTextColor.RED) - ) - add( - Component.text("Il y a écrit que un de ces 3 citoyens", NamedTextColor.DARK_RED) - ) - add( - Component.text("est un loup-garou.", NamedTextColor.DARK_RED) - ) + val finalLore = + buildList { + add( + Component.text("C'est une liste de nom.", NamedTextColor.RED), + ) + add( + Component.text("Il y a écrit que un de ces 3 citoyens", NamedTextColor.DARK_RED), + ) + add( + Component.text("est un loup-garou.", NamedTextColor.DARK_RED), + ) - val players = Game.current?.playersMutable?.shuffled().orEmpty() + val players = + Game.current + ?.remainingPlayer + ?.shuffled() + .orEmpty() - val (villagers, werewolves) = players.partition { - Role.getRole(it)?.lg == false + val (villagers, werewolves) = + players.partition { + Role.getRole(it)?.team != Role.Team.LG + } + + val lg = werewolves.firstOrNull() + val names = mutableListOf() + + if (lg != null) names.add(lg) + names.addAll(villagers.take(2)) + + val colors = NamedColors.namedColors.shuffled().toMutableList() + + names.shuffled().forEach { + val color = colors.removeFirst() + add(Component.text("- ").append(it.displayName()).color(color)) + } + + if (isEmpty()) { + add(Component.text("nothing", NamedTextColor.DARK_RED, TextDecoration.OBFUSCATED)) + } } - - val lg = werewolves.firstOrNull() - val names = mutableListOf() - - if (lg != null) names.add(lg) - names.addAll(villagers.take(2)) - - val colors = NamedColors.namedColors.shuffled().toMutableList() - - names.shuffled().forEach { - val color = colors.removeFirst() - add(Component.text("- ").append(it.displayName()).color(color)) - } - - if (isEmpty()) { - add(Component.text("nothing", NamedTextColor.DARK_RED, TextDecoration.OBFUSCATED)) - } - } ItemStack(Material.PAPER).apply { - itemMeta = itemMeta.apply { - displayName(Component.text("Liste de nom", NamedTextColor.GOLD)) - lore(finalLore) - } + itemMeta = + itemMeta.apply { + displayName(Component.text("Liste de nom", NamedTextColor.GOLD)) + lore(finalLore) + } } - }); + }), + ; private var cachedItem: ItemStack? = null @@ -206,21 +230,31 @@ enum class CustomItems(val cache: Boolean, val supplier: () -> ItemStack) { } } - data object NamedColors { - val namedColors = listOf( - NamedTextColor.DARK_RED, - NamedTextColor.RED, - NamedTextColor.GOLD, - NamedTextColor.YELLOW, - NamedTextColor.DARK_GREEN, - NamedTextColor.GREEN, - NamedTextColor.AQUA, - NamedTextColor.DARK_AQUA, - NamedTextColor.DARK_BLUE, - NamedTextColor.BLUE, - NamedTextColor.LIGHT_PURPLE, - NamedTextColor.DARK_PURPLE - ) + interface DamageableCrossbow : + Damageable, + CrossbowMeta + interface DamageablePotion : + Damageable, + PotionMeta { + override fun clone(): DamageablePotion } -} \ No newline at end of file + + data object NamedColors { + val namedColors = + listOf( + NamedTextColor.DARK_RED, + NamedTextColor.RED, + NamedTextColor.GOLD, + NamedTextColor.YELLOW, + NamedTextColor.DARK_GREEN, + NamedTextColor.GREEN, + NamedTextColor.AQUA, + NamedTextColor.DARK_AQUA, + NamedTextColor.DARK_BLUE, + NamedTextColor.BLUE, + NamedTextColor.LIGHT_PURPLE, + NamedTextColor.DARK_PURPLE, + ) + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/roles/Child.kt b/src/main/kotlin/fr/azur/tcoww/roles/Child.kt index fa0589b..a9248cd 100644 --- a/src/main/kotlin/fr/azur/tcoww/roles/Child.kt +++ b/src/main/kotlin/fr/azur/tcoww/roles/Child.kt @@ -2,21 +2,22 @@ package fr.azur.tcoww.roles import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.Material import org.bukkit.NamespacedKey -import org.bukkit.entity.Player -class Child : Role { - override fun handle(player: Player) {} - - override fun onDeath(player: Player) {} - - override var lg = false - override var id = NamespacedKey("tcoww", "child") - override val displayName = Component.text("Petite Fille") +object Child : Role { + override val id = NamespacedKey("tcoww", "child") + override val team = Role.Team.Villager + override val displayName = Component.text("Petite Fille", NamedTextColor.LIGHT_PURPLE) + override val icon = Material.MAGENTA_WOOL + override val order: Int = 2 override val hasPowerCommand = false override val description = - Component.text("Extrêmement discrette et au coeur du risque.", NamedTextColor.BLUE).appendNewline() - .append( - Component.text("Vous n'êtes pas obliger de dormir la nuit, vous pouvez donc observer les loups le soir.", NamedTextColor.BLUE) - ) -} \ No newline at end of file + listOf( + Component.text("Extrêmement discrette et au coeur du risque.", NamedTextColor.BLUE), + Component.text( + "Vous n'êtes pas obliger de dormir la nuit, vous pouvez donc observer les loups le soir.", + NamedTextColor.BLUE, + ), + ) +} diff --git a/src/main/kotlin/fr/azur/tcoww/roles/FortuneTeller.kt b/src/main/kotlin/fr/azur/tcoww/roles/FortuneTeller.kt index 6d9f66b..e2b356d 100644 --- a/src/main/kotlin/fr/azur/tcoww/roles/FortuneTeller.kt +++ b/src/main/kotlin/fr/azur/tcoww/roles/FortuneTeller.kt @@ -3,23 +3,27 @@ package fr.azur.tcoww.roles import fr.azur.tcoww.items.CustomItems import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.entity.Player -class FortuneTeller : Role { +object FortuneTeller : Role { override fun handle(player: Player) { player.inventory.addItem(CustomItems.CrystalBall.item) } - override fun onDeath(player: Player) {} - - override var lg = false + override val team = Role.Team.Villager override var id = NamespacedKey("tcoww", "fortune_teller") - override val displayName = Component.text("Voyante") + override val icon = Material.GLASS + override val order: Int = 3 + override val displayName = Component.text("Voyante", NamedTextColor.AQUA) override val hasPowerCommand = true override val description = - Component.text("Vous voyez des choses mais quoi ?.", NamedTextColor.BLUE).appendNewline() - .append( - Component.text("Tout les 2 jours vous pouvez regarder le role d'un joueur.", NamedTextColor.BLUE) - ) -} \ No newline at end of file + listOf( + Component.text("Vous voyez des choses mais quoi ?.", NamedTextColor.BLUE), + Component + .text("Tout les 2 jours vous pouvez regarder le role d'un joueur grâce à votre ", NamedTextColor.BLUE) + .append(CustomItems.CrystalBall.item.displayName()) + .append(Component.text(".", NamedTextColor.BLUE)), + ) +} diff --git a/src/main/kotlin/fr/azur/tcoww/roles/Hunter.kt b/src/main/kotlin/fr/azur/tcoww/roles/Hunter.kt index cd8db61..2830960 100644 --- a/src/main/kotlin/fr/azur/tcoww/roles/Hunter.kt +++ b/src/main/kotlin/fr/azur/tcoww/roles/Hunter.kt @@ -3,32 +3,32 @@ package fr.azur.tcoww.roles import fr.azur.tcoww.items.CustomItems import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.entity.Player -class Hunter : Role { +object Hunter : Role { override fun handle(player: Player) { player.inventory.addItem(CustomItems.BlasTechDL44.item) } - override fun onDeath(player: Player) { - TODO("Not yet implemented") - } - - override var lg = false + override val team = Role.Team.Villager override var id = NamespacedKey("tcoww", "hunter") - override val displayName = Component.text("Chaseur") + override val displayName = Component.text("Chaseur", NamedTextColor.GOLD) + override val icon = Material.ARROW + override val order: Int = 5 override val hasPowerCommand = false override val description = - Component.text( - "Vous êtes la personne, la plus redouter des animaux (et en particulier des loups).", - NamedTextColor.BLUE - ).appendNewline() - .append( - Component.text("Vous possedez un ", NamedTextColor.BLUE) - .append(CustomItems.BlasTechDL44.item.displayName()) - .append( - Component.text(" qui permet de one shot n'importe quoi... (Usage Unique.)", NamedTextColor.BLUE) - ) - ) -} \ No newline at end of file + listOf( + Component.text( + "Vous êtes la personne, la plus redouter des animaux (et en particulier des loups).", + NamedTextColor.BLUE, + ), + Component + .text("Vous possedez un ", NamedTextColor.BLUE) + .append(CustomItems.BlasTechDL44.item.displayName()) + .append( + Component.text(" qui permet de one shot n'importe quoi... (Usage Unique)", NamedTextColor.BLUE), + ), + ) +} diff --git a/src/main/kotlin/fr/azur/tcoww/roles/Role.kt b/src/main/kotlin/fr/azur/tcoww/roles/Role.kt index db7e86b..a5c6b72 100644 --- a/src/main/kotlin/fr/azur/tcoww/roles/Role.kt +++ b/src/main/kotlin/fr/azur/tcoww/roles/Role.kt @@ -2,48 +2,87 @@ package fr.azur.tcoww.roles import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.entity.Player import org.bukkit.persistence.PersistentDataType interface Role { - fun handle(player: Player) - fun onDeath(player: Player) - val lg: Boolean + enum class Team { + LG { + override val displayName = Component.text("loups-garous").color(NamedTextColor.DARK_RED) + }, + Villager { + override val displayName: Component = Component.text("villageois", NamedTextColor.GREEN) + }, + Solo { + override val displayName: Component = Component.text("solo", NamedTextColor.YELLOW) + }, ; + + abstract val displayName: Component + } + + fun handle(player: Player) {} + + fun onDeath(player: Player) {} + + fun onVote(player: Player) {} + val id: NamespacedKey + val icon: Material + val order: Int + val team: Team val displayName: Component val hasPowerCommand: Boolean - val description: Component + val description: List + val lineDescription: Component + get() { + return Component.empty().apply { + description.forEach { + append(it) + appendNewline() + } + } + } companion object { var registerRoles = hashMapOf() - private val rolekey = NamespacedKey("tcoww", "role") - fun setRole(player: Player, role: Role) { - player.persistentDataContainer.set( - rolekey, - PersistentDataType.STRING, - role.id.toString() + private val roleKey = NamespacedKey("tcoww", "role") + + fun setRole( + player: Player, + role: Role, + ) { + player.sendMessage( + Component.text("Votre role est ", NamedTextColor.DARK_AQUA).append(role.displayName), ) player.sendMessage( - Component.text("Votre role est ").append(role.displayName).color(NamedTextColor.DARK_AQUA) + role.lineDescription.append { + if (role.team == Team.Solo) { + Component.text("Vous gagnez Seul.", NamedTextColor.AQUA) + } else { + Component + .text("Vous gagnez avec les ", NamedTextColor.AQUA) + .append(role.team.displayName) + .append(Component.text(".", NamedTextColor.AQUA)) + } + }, ) - player.sendMessage(role.description.appendNewline().append { - if (role.lg) - Component.text("Vous gagnez avec les loups-garous.", NamedTextColor.AQUA) - else - Component.text("Vous gagnez avec les villageois.", NamedTextColor.AQUA) - }) - role.handle(player) + + player.persistentDataContainer.set(roleKey, PersistentDataType.STRING, role.id.toString()) } fun getRole(player: Player): Role? { - val rolestr = player.persistentDataContainer.get(rolekey, PersistentDataType.STRING) - if (rolestr == null) return null - return registerRoles[NamespacedKey.fromString(rolestr)] + val roleKey = player.persistentDataContainer.get(roleKey, PersistentDataType.STRING) ?: return null + return registerRoles[NamespacedKey.fromString(roleKey)] } + var Player.werewolfRole: Role + get() = getRole(this)!! + set(role) = setRole(this, role) + fun registerRole(role: Role) { - registerRoles.put(role.id, role) + registerRoles[role.id] = role } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/fr/azur/tcoww/roles/Villager.kt b/src/main/kotlin/fr/azur/tcoww/roles/Villager.kt index 6808fbb..bc16f67 100644 --- a/src/main/kotlin/fr/azur/tcoww/roles/Villager.kt +++ b/src/main/kotlin/fr/azur/tcoww/roles/Villager.kt @@ -2,25 +2,19 @@ package fr.azur.tcoww.roles import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.Material import org.bukkit.NamespacedKey -import org.bukkit.entity.Player -class Villager : Role { - override fun handle(player: Player) { - - } - - override fun onDeath(player: Player) { - - } - - override var lg: Boolean = false +object Villager : Role { + override val team = Role.Team.Villager override var id = NamespacedKey("tcoww", "villager") - override val displayName = Component.text("Villageois") + override val displayName = Component.text("Villageois", NamedTextColor.GRAY) + override val icon = Material.DIRT + override val order: Int = 0 override val hasPowerCommand = false override val description = - Component.text("En tant que villageois, vous n'avez aucun pouvoir.", NamedTextColor.BLUE).appendNewline() - .append( - Component.text("Profiter en pour risquer pour trouver des indices ! ^^", NamedTextColor.BLUE) - ) -} \ No newline at end of file + listOf( + Component.text("En tant que villageois, vous n'avez aucun pouvoir.", NamedTextColor.BLUE), + Component.text("Profiter en pour risquer pour trouver des indices ! ^^", NamedTextColor.BLUE), + ) +} diff --git a/src/main/kotlin/fr/azur/tcoww/roles/Werewolf.kt b/src/main/kotlin/fr/azur/tcoww/roles/Werewolf.kt index 472d148..dc61499 100644 --- a/src/main/kotlin/fr/azur/tcoww/roles/Werewolf.kt +++ b/src/main/kotlin/fr/azur/tcoww/roles/Werewolf.kt @@ -1,25 +1,32 @@ package fr.azur.tcoww.roles +import fr.azur.tcoww.Tcoww +import fr.azur.tcoww.items.CustomItems import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.entity.Player -class Werewolf : Role { - override fun handle(player: Player) {} - - override fun onDeath(player: Player) {} - - override var lg = true +object Werewolf : Role { + override val team = Role.Team.LG override var id = NamespacedKey("tcoww", "werewolf") - override val displayName = Component.text("Loup-Garou") + override val displayName = Component.text("Loup-Garou", NamedTextColor.DARK_GRAY) + override val icon = Material.BONE + override val order: Int = 1 override val hasPowerCommand = false override val description = - Component.text("Pour la faire courte, vous avez faim, très faim.", NamedTextColor.BLUE).appendNewline() - .append( - Component.text( - "Votre but est de tuer les villageois. Sans vous faire atraper et voter. Toute les nuits, vous pouvez vous tranformer en loup pour manger un villageois.", - NamedTextColor.BLUE - ) - ) -} \ No newline at end of file + listOf( + Component.text("Pour la faire courte, vous avez faim, très faim.", NamedTextColor.BLUE), + Component.text( + "Votre but est de tuer les villageois. Sans vous faire atraper et voter. Toute les nuits, vous pouvez vous tranformer en loup pour manger un villageois.", + NamedTextColor.BLUE, + ), + ) + + override fun handle(player: Player) { + val tfItem = CustomItems.WereWolfTransformItem.item + player.inventory.addItem(tfItem) + player.setCooldown(tfItem, ((Tcoww.config.getInt("duration.day") + Tcoww.config.getInt("duration.day")) * 20)) + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/roles/Witch.kt b/src/main/kotlin/fr/azur/tcoww/roles/Witch.kt index 8ae71fb..6d8ca22 100644 --- a/src/main/kotlin/fr/azur/tcoww/roles/Witch.kt +++ b/src/main/kotlin/fr/azur/tcoww/roles/Witch.kt @@ -3,27 +3,28 @@ package fr.azur.tcoww.roles import fr.azur.tcoww.items.CustomItems import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.entity.Player -class Witch : Role { +object Witch : Role { override fun handle(player: Player) { player.inventory.addItem(CustomItems.DeathPotion.item) player.inventory.addItem(CustomItems.HealPotion.item) } - override fun onDeath(player: Player) {} - - override var lg = false + override val team = Role.Team.Villager override var id = NamespacedKey("tcoww", "witch") override val displayName = Component.text("Sorcière") + override val icon = Material.GLASS_BOTTLE + override val order: Int = 4 override val hasPowerCommand = true override val description = - Component.text("Une potion = Une solution.", NamedTextColor.BLUE).appendNewline() - .append( - Component.text( - "Vous possédez deux potions : une pour tuer et une pour ressusciter quelqu'un.", - NamedTextColor.BLUE - ) - ).appendNewline() -} \ No newline at end of file + listOf( + Component.text("Une potion = Une solution.", NamedTextColor.BLUE), + Component.text( + "Vous possédez deux potions : une pour tuer et une pour ressusciter quelqu'un.", + NamedTextColor.BLUE, + ), + ) +} diff --git a/src/main/kotlin/fr/azur/tcoww/ui/CustomUI.kt b/src/main/kotlin/fr/azur/tcoww/ui/CustomUI.kt new file mode 100644 index 0000000..35ca6e1 --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/ui/CustomUI.kt @@ -0,0 +1,11 @@ +package fr.azur.tcoww.ui + +import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.event.inventory.InventoryCloseEvent +import org.bukkit.inventory.InventoryHolder + +interface CustomUI : InventoryHolder { + fun onClick(event: InventoryClickEvent) {} + + fun onClose(event: InventoryCloseEvent) {} +} diff --git a/src/main/kotlin/fr/azur/tcoww/ui/GameConfig.kt b/src/main/kotlin/fr/azur/tcoww/ui/GameConfig.kt new file mode 100644 index 0000000..08f9449 --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/ui/GameConfig.kt @@ -0,0 +1,121 @@ +package fr.azur.tcoww.ui + +import fr.azur.tcoww.Tcoww +import fr.azur.tcoww.roles.Role +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor +import org.bukkit.NamespacedKey +import org.bukkit.event.inventory.InventoryClickEvent +import org.bukkit.event.inventory.InventoryCloseEvent +import org.bukkit.inventory.Inventory +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.Damageable +import java.util.concurrent.CompletableFuture +import kotlin.math.ceil + +class GameConfig( + playerCount: Int, +) : CustomUI { + // [index, [role key, amount]] + val rolesConfig = hashMapOf>() + val size = (Role.registerRoles.count() / 9 + 1) * 9 + val future = CompletableFuture>() + + private val inventory = + Tcoww.server.createInventory(this, size, Component.text("Game Config.", NamedTextColor.GREEN)).apply { + Role.registerRoles.values.sortedBy { it.order }.onEachIndexed { index, role -> + setItem(index, createItem(index, role)) + } + } + + init { + val werewolfCount = ceil((playerCount * (Tcoww.config.getInt("werewolf-default-percentage") / 100f))).toInt() + editItem(0, playerCount - werewolfCount) + editItem(1, werewolfCount) + } + + private fun createItem( + index: Int, + role: Role, + ): ItemStack { + rolesConfig[index] = Pair(role.id, 0) + + return ItemStack.of(role.icon).apply { + itemMeta = + (itemMeta as Damageable).apply { + lore( + role.description, + ) + itemName( + role.displayName, + ) + setMaxStackSize(1) + setMaxDamage(1) + damage = 1 + } + } + } + + private fun editItem( + index: Int, + newAmount: Int, + ) { + if (newAmount !in 0..99) throw IllegalArgumentException("Amount must be in 0 and 99 !") + rolesConfig[index] = Pair(rolesConfig[index]!!.first, newAmount) + val item = inventory.getItem(index) ?: return + item.itemMeta = + (item.itemMeta as Damageable).apply { + if (newAmount == 0) { + setMaxStackSize(1) + setMaxDamage(1) + damage = 1 + } else { + damage = 0 + setMaxStackSize(99) + item.amount = newAmount + } + } + } + + override fun getInventory(): Inventory = inventory + + override fun onClick(event: InventoryClickEvent) { + event.isCancelled = true + val index = event.slot + if (index !in 0.., +) : CustomUI { + val size = (players.count() / 9 + 1) * 9 + val future = CompletableFuture() + + private val inventory = + Tcoww.server.createInventory(this, size, Component.text("Select a player.", NamedTextColor.GREEN)).apply { + players.forEachIndexed { index, player -> + val item = + ItemStack.of(Material.PLAYER_HEAD).apply { + itemMeta = + (itemMeta as SkullMeta).apply { + playerProfile = player.playerProfile + } + } + setItem(index, item) + } + } + + override fun getInventory(): Inventory = inventory + + override fun onClick(event: InventoryClickEvent) { + val index = event.slot + if (index !in 0.. - skinsRestorer.skinStorage.setCustomSkinData("tcoww_$index", SkinProperty.of(value, signature)) - maxSkinId = index - } - } - - fun applyWerewolfFur(player: Player) { - val skin = skinsRestorer.playerStorage.getSkinIdOfPlayer(player.uniqueId) - Stockage.oldPlayerSkin[player.uniqueId] = skin.getOrNull() - - val result = skinsRestorer.skinStorage.findOrCreateSkinData("tcoww_${getWerewolfFur(player.uniqueId)}") - - if (!result.isEmpty) { - skinsRestorer.playerStorage.setSkinIdOfPlayer(player.uniqueId, result.get().identifier) - skinsRestorer.getSkinApplier(Player::class.java).applySkin(player) - } - } - - fun unApplySkin(player: Player) { - val skin = Stockage.oldPlayerSkin[player.uniqueId] - if (skin == null) { - skinsRestorer.playerStorage.removeSkinIdOfPlayer(player.uniqueId) - } else { - skinsRestorer.playerStorage.setSkinIdOfPlayer(player.uniqueId,skin) - } - skinsRestorer.getSkinApplier(Player::class.java).applySkin(player) - } - - private fun getWerewolfFur(playerUUID: UUID): Int { - return Stockage.wwPlayerFur[playerUUID] - ?: randomFur(playerUUID) - } - - private fun randomFur(playerUUID: UUID): Int { - val id = if (maxSkinId == 0) 0 else Random(playerUUID.mostSignificantBits xor playerUUID.leastSignificantBits).nextInt(maxSkinId) - Stockage.wwPlayerFur[playerUUID] = id - return id - } - -} \ No newline at end of file diff --git a/src/main/kotlin/fr/azur/tcoww/utils/Stockage.kt b/src/main/kotlin/fr/azur/tcoww/utils/Stockage.kt deleted file mode 100644 index 5e2a562..0000000 --- a/src/main/kotlin/fr/azur/tcoww/utils/Stockage.kt +++ /dev/null @@ -1,13 +0,0 @@ -package fr.azur.tcoww.utils - -import net.skinsrestorer.api.property.SkinIdentifier -import org.bukkit.Location -import java.util.* - - -object Stockage { - var backLocation = mutableMapOf() - var vote = mutableMapOf() - var oldPlayerSkin = mutableMapOf() - var wwPlayerFur = mutableMapOf() -} diff --git a/src/main/kotlin/fr/azur/tcoww/utils/VoiceChatPlugin.kt b/src/main/kotlin/fr/azur/tcoww/utils/VoiceChatPlugin.kt new file mode 100644 index 0000000..3c7ef78 --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/utils/VoiceChatPlugin.kt @@ -0,0 +1,58 @@ +package fr.azur.tcoww.utils + +import de.maxhenkel.voicechat.api.Group +import de.maxhenkel.voicechat.api.VoicechatPlugin +import de.maxhenkel.voicechat.api.VoicechatServerApi +import de.maxhenkel.voicechat.api.events.EventRegistration +import de.maxhenkel.voicechat.api.events.VoicechatServerStartedEvent +import org.bukkit.entity.Player +import java.util.UUID +import kotlin.random.Random + +object VoiceChatPlugin : VoicechatPlugin { + lateinit var api: VoicechatServerApi + lateinit var werewolfGroup: Group + + override fun getPluginId(): String = "tcoww" + + override fun registerEvents(registration: EventRegistration) { + registration.registerEvent(VoicechatServerStartedEvent::class.java, this::onServerStarted) + } + + private fun onServerStarted(event: VoicechatServerStartedEvent) { + api = event.voicechat + werewolfGroup = + api + .groupBuilder() + .setPersistent(true) + .setName("werewolf") + .setPassword(Random.nextInt().toString()) + .setType(Group.Type.NORMAL) + .setHidden(true) + .build() + } + + fun addWerewolf(player: Player) { + val connection = api.getConnectionOf(player.uniqueId) ?: return + connection.group = werewolfGroup + } + + fun createSoloGroup(player: Player) { + val connection = api.getConnectionOf(player.uniqueId) ?: return + val soloGroup = + api + .groupBuilder() + .setName(UUID.randomUUID().toString()) + .setHidden(true) + .setPassword(Random.nextInt().toString()) + .setType(Group.Type.ISOLATED) + .setPersistent(false) + .build() + connection.group = soloGroup + } + + fun degroupPlayer(player: Player) { + val connection = api.getConnectionOf(player.uniqueId) ?: return + connection.group = null + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/utils/skins/Manager.kt b/src/main/kotlin/fr/azur/tcoww/utils/skins/Manager.kt new file mode 100644 index 0000000..7fd32ef --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/utils/skins/Manager.kt @@ -0,0 +1,77 @@ +package fr.azur.tcoww.utils.skins + +import fr.azur.tcoww.Tcoww +import net.skinsrestorer.api.SkinsRestorer +import net.skinsrestorer.api.SkinsRestorerProvider +import net.skinsrestorer.api.property.SkinIdentifier +import net.skinsrestorer.api.property.SkinProperty +import org.bukkit.entity.Player +import java.util.UUID +import kotlin.jvm.optionals.getOrNull +import kotlin.random.Random + +object Manager { + var maxSkinId: Int = 0 + private lateinit var skinsRestorer: SkinsRestorer + var oldPlayerSkin = mutableMapOf() + var wwPlayerFur = mutableMapOf() + + fun handle() { + skinsRestorer = SkinsRestorerProvider.get() + reloadSkin() + } + + fun reloadSkin() { + val skinsValue = + Tcoww.config + .getList("werewolf-skins") + .orEmpty() + .mapNotNull { it as? WerewolfSkin } + + wwPlayerFur.clear() + + maxSkinId = skinsValue.size + skinsValue.forEachIndexed { index, skin -> + skinsRestorer.skinStorage.setCustomSkinData("tcoww$index", SkinProperty.of(skin.value, skin.signature)) + } + } + + fun applyWerewolfFur(player: Player) { + val skin = skinsRestorer.playerStorage.getSkinIdOfPlayer(player.uniqueId) + oldPlayerSkin[player.uniqueId] = skin.getOrNull() + + val result = skinsRestorer.skinStorage.findOrCreateSkinData("tcoww_${getWerewolfFur(player.uniqueId)}") + + if (!result.isEmpty) { + skinsRestorer.playerStorage.setSkinIdOfPlayer(player.uniqueId, result.get().identifier) + skinsRestorer.getSkinApplier(Player::class.java).applySkin(player) + } + } + + fun unapplySkin(player: Player) { + val skin = oldPlayerSkin[player.uniqueId] + if (skin == null) { + skinsRestorer.playerStorage.removeSkinIdOfPlayer(player.uniqueId) + } else { + skinsRestorer.playerStorage.setSkinIdOfPlayer(player.uniqueId, skin) + } + skinsRestorer.getSkinApplier(Player::class.java).applySkin(player) + } + + private fun getWerewolfFur(playerUUID: UUID): Int = + wwPlayerFur[playerUUID] + ?: randomFur(playerUUID) + + private fun randomFur(playerUUID: UUID): Int { + val id = + if (maxSkinId == 0) { + 0 + } else { + Random(playerUUID.mostSignificantBits xor playerUUID.leastSignificantBits).nextInt( + maxSkinId, + ) + } + wwPlayerFur[playerUUID] = id + return id + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/utils/skins/WerewolfSkin.kt b/src/main/kotlin/fr/azur/tcoww/utils/skins/WerewolfSkin.kt new file mode 100644 index 0000000..59fc759 --- /dev/null +++ b/src/main/kotlin/fr/azur/tcoww/utils/skins/WerewolfSkin.kt @@ -0,0 +1,22 @@ +package fr.azur.tcoww.utils.skins + +import org.bukkit.configuration.serialization.ConfigurationSerializable + +data class WerewolfSkin( + val value: String, + val signature: String, +) : ConfigurationSerializable { + constructor(args: MutableMap) : this( + args["value"] as String, + args["signature"] as String, + ) + + override fun serialize(): Map { + val data: MutableMap = HashMap() + + data["value"] = value + data["signature"] = signature + + return data + } +} diff --git a/src/main/kotlin/fr/azur/tcoww/voicechat/VoiceChatPlugin.kt b/src/main/kotlin/fr/azur/tcoww/voicechat/VoiceChatPlugin.kt deleted file mode 100644 index 663a5d5..0000000 --- a/src/main/kotlin/fr/azur/tcoww/voicechat/VoiceChatPlugin.kt +++ /dev/null @@ -1,14 +0,0 @@ -package fr.azur.tcoww.voicechat - -import de.maxhenkel.voicechat.api.VoicechatPlugin -import de.maxhenkel.voicechat.api.events.EventRegistration - -class VoiceChatPlugin: VoicechatPlugin { - override fun getPluginId(): String { - return "tcow" - } - - override fun registerEvents(registration: EventRegistration) { - - } -} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 94dd547..4c270bf 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,38 +1,35 @@ -spawnLocation: - ==: org.bukkit.Location - world: world - x: 0.0 - y: 0.0 - z: 0.0 - pitch: 0.0 - yaw: 0.0 -lobbyLocation: - ==: org.bukkit.Location - world: world - x: 0.0 - y: 0.0 - z: 0.0 - pitch: 0.0 - yaw: 0.0 +# Bukkit Location +spawn-location: null + +# Bukkit Location +lobby-location: null + +# List of Bukkit Location +bed-locations: null + duration: # In seconds day: 600 vote: 120 night: 300 crepuscular: 20 -wwcount: 10 + +werewolf-default-percentage: 20 + # The skin value -wwskinsvalue: [ - "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQ2NzI1ODQxMCwKICAicHJvZmlsZUlkIiA6ICJjMGYzYjI3YTUwMDE0YzVhYjIxZDc5ZGRlMTAxZGZlMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJDVUNGTDEzIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2Y5NmM4OWUwZWYwZmVlZjZkODc4ZDUzYzQ4OWIyMzliNDdlNmViODQyZDJmM2MzZTlhZDdkMjliZmYxYTM0OWUiCiAgICB9CiAgfQp9", - "ewogICJ0aW1lc3RhbXAiIDogMTYxNTYxMTkwOTY4MCwKICAicHJvZmlsZUlkIiA6ICIwMGM2Yjk0YTY5YmU0MzY3OTkwOTQxNjFjMjAxOWI3ZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJLQUVWRVJZIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2I0MGRjNTcxZGUwZGQ4ZmQ5NzBjNzNmOTE2NGJjMTQ0Njk1MWFlNDhkNWFiZTQyMzI5MGVlYjFhODc4NDU1ZmUiCiAgICB9CiAgfQp9", - "ewogICJ0aW1lc3RhbXAiIDogMTc0Nzk4MDc5ODQyMywKICAicHJvZmlsZUlkIiA6ICI2NWI5NTU1YWQyMGU0NWM5YjFkNmU3MjQwNjU0NTBkNCIsCiAgInByb2ZpbGVOYW1lIiA6ICJKYXZhUHJvZmlsZU5hbWVYIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzJlZTlmNjcxYzFmNjY4Y2IwYWUwNGE5YzhiZWM0OTVlYTVmNzNmNTNmYmY3ZjM5MmNkYjdlMTc1ZmVjZDFjYmUiCiAgICB9CiAgfQp9", - "ewogICJ0aW1lc3RhbXAiIDogMTY0Mjc4ODk3NDg1NSwKICAicHJvZmlsZUlkIiA6ICIzYzE0YmVkNDFiOGE0MDIzOGM3MDgzMTA1NzEwMTZmYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJOb2Jpa28iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWZlNzIzMDdjZTEyNmI1Y2I0ZDQ0ZGFlZTcwZDI1ZmQwNDMwOGJjN2M0MzI4OWM3ZDk3MDY4NDY5NWI2MGJhIgogICAgfQogIH0KfQ==" -] # The skin signature (see mineskin.org) -wwskinssignature: [ - "uWIu/2R3zImj87H7x//O/04eJ1SwsHvLSxaj1YQuI1vBndUVHhN42Ja7AOJoAieVO8yN1qn/rJj1oK5z5koQ2fZwjNCc0mKTrakCMWGqjaAImDw8RWriUQ3ClPCw6NtCmB1qVUp60kUEpGha/btUSsAEUnVZ0ghM4SXTcS2izbDe/dRfbi5EDr2Uue3sz6+med3hjecZzrKJUX19wP1WwPifEOH2X/smzzGOdqlQtylMZQh3nNeho/GBwbDVXsXsR6LcDgoInDnw63cDV7n4dTs6giGmcx0knhDWH24Z/vrgNSqzbNY9hIgVBNWUqs/1o7/xrbK1HilYBPAiVO0F6+vJOpzdFrpEZVr0M++u+X2Zkt1sfshKZqt0O07KbH8h4xj3J+6iDF5RHHFGmZy0awFGZGIi8wqlffwQfZ+l7nPU1hpMD5DkArxBWJWgnquyCNpQ44OlmTpPRa/gopRpuMwJ1r6vDPhgIavJX6cKQ2lKTYKG2/HB+ZEl/IUtuXxKO7bFe4KOvjJpMwBjOmzqbn2sk3GqbSg8NfNMFA4FjRBvHXOaMsDCqz0MJxLFKvIfYRVWG8XAU6BU82RoS3qGFSOhI6N/DvD7dx1V40q52iWv2j4/S41P5zrtMqQm7wofocptz6sS7GLE1u9rPCBLRIck0wzi3OF7MV2p4wlw6lw=", - "kVGwx98YPc6tIZ306TiGI5eoK4v7oEjIvCaOPS03jq4LjBWV12NBTWW67u+HrI2/2m3r8pvAyx1Ddpw4YWyaDbaG0FvLuurWbETqtwvyvVx7R3BZHgw2EnVOYk4+WPmA8xUgzoIbZF/Ch4bSqP7UlZy7/fz4AQwFK/qLMzApOAeV4Kzn4p6+MK2uOkfSjGgwxqAO/+TZj6u01mk1NKNh4ors9RGDG3DBHZKSxTG/PzY5ErKABRXkB/RBMA5IvU5Rzn5cH+Sfkus/7LtYp5u+5i+HcpN/klyBBw4D5di3WzFOAIX78ZiyKzKzWpSN0z6Cb2DZdo1ufeZH9mw8nv+A8VfpGXwphwde+oGBP4l4OffE7YvbnWyVHmlG0L36iI2/FkWQl91GIT15YBHrjeQ9pmvbzCQUMyAHi2jZePTTcT1rDnSzBk7fc9IwfcBRNyqbveTNu9zikfx0W6GnXAbV4qOTIIVEHlpxQ9KW017sqmgiF5l/3ZVwqbEQzglNehYHA55vRfKY0HKbGB54k1oTnM3X7mNXIu6fk8dVgCvT8lVdDm3LWcE6aWF8Yp6QrXNvTNW1yxSRAhigsHrvbajp2Odg18lMTng0oh/4JiYOQAgb6tFdRtQ4nrSVHRBOEvY09IRFzVTTd7n2JaYZ6QcCMOiKOX25fv22rbjSeAZ/Whk=", - "wGc2rNbc7+nziEDMKFoBIltHZwx5PQfsfMGyRTfTUdtVi3O4iu0idcpTsTVJ80njIFZvmLpzlwjPu6ULrXJwgQQyGCNdp60jQMl9vGjzgJzs6uqhSCke3EvjOCuAGkv2ScRY5hDGQOnIruxwmgYgDeXHnujt+zTBvW+imxLVaZhXoKVPyqlvm6njWp0XECyAi8DFKbzIdDVp+NsRzIGjKeVoMgWd4xlNazUZGgTsXNCD/+aZOJ1LxA51I8Wgsm888MUXnaGhNI3U4jJNKHAPZMS4++JEuwWzlptJdZIa1jOfwMD6HvIPKEmC5+eDCRFvPIEh84VqErtNTPEUAz7wZAJvO+j+x5A/9VnQmKJhEBxBjlw1Ky+mQcLJnRX/x9jc4EvEd9gWGIUj46y3IF8jWn71eXvinSJ4Op4LQEiv5BfuyMTfY2xwFTlGWjdYF6Xnac+Gz6+E1gjCBSuqKWd56QFDcrqCcvbG50ERhenCUEhUgI33rXNxS/hwz2iClVM26GFJlUtZkZ7/021FjEQNLEYivI1ZkHe9ip8sxx2QVKd5k7Ui/hXkP4xSal3okL4Ar/cThMh0aoWzziYsoAahtoxFWEags7lNOffMoLGmPbgGVRUGHogNu2CES0SNs4AhHVUVERo8OTJHx46XJxXqvLzeEn6zXFD63XXQR8AyXTQ=", - "hJ/FhIMQY9G/BqOvGJ0nhuJk/7Y/q/unCpeC7LxGvcYjXzsY/kcInwUzgfjRqNI0oI5ggOAdxIiaGvBRqWCshjxcx6iRyJZBMKwFchM1baHntRl22yxvBA16gpMxbWTihQ0Jtz9m/Dj8clYgyEkMOKFEOya5YiyyqjK+YOl5xWiM1pGAomFixqr7VBLk/NE7e+qYXuFjDl3IZ1OP+tgdgyjkqUZE3OBGQfXP6wvTFjgk/maCPUmzffnbw/yH4JZIa3N/vhK+jzowcV+ymZK/9+10ge8hIZ5LZPdU90xLWd2zPYFjju/vr9TFWUG4YkV8l1vSsG7P8MYjMKFh/YQoTyyjJUZw9YGfnRENZrdegttUxefJywpBgp0xVt5vyAMM9XjTEtwK/A5gef0fD52lKWpwD6xamPBnhb8yRPUnncapGBrQvFhB8uQnkS8BKqtiJyz8XJHg8quzUXjYd+Ywn5p+lzP5zsDXQDYOfcm4FZGYp3oFwJZz1s4YOjP8Abjd+4v0sQIcP+Kj8lBzrADQSvTIJaQZO/emnpkZYoW/ggSJLa+BrRUXK5gNHdZzUI/EDOJggrGn3ezSLd96DyDlosG+lGM/EpuiB504YNzQfrm1scVbk9R4YHNhy+sau04DJcRY0p52qeaVDswMkfjUA6JBvBFT9SqQeB7q9qRwLrk=" -] +werewolf-skins: + - ==: fr.azur.tcoww.utils.skins.WerewolfSkin + value: "ewogICJ0aW1lc3RhbXAiIDogMTYxNzQ2NzI1ODQxMCwKICAicHJvZmlsZUlkIiA6ICJjMGYzYjI3YTUwMDE0YzVhYjIxZDc5ZGRlMTAxZGZlMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJDVUNGTDEzIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2Y5NmM4OWUwZWYwZmVlZjZkODc4ZDUzYzQ4OWIyMzliNDdlNmViODQyZDJmM2MzZTlhZDdkMjliZmYxYTM0OWUiCiAgICB9CiAgfQp9" + signature: "uWIu/2R3zImj87H7x//O/04eJ1SwsHvLSxaj1YQuI1vBndUVHhN42Ja7AOJoAieVO8yN1qn/rJj1oK5z5koQ2fZwjNCc0mKTrakCMWGqjaAImDw8RWriUQ3ClPCw6NtCmB1qVUp60kUEpGha/btUSsAEUnVZ0ghM4SXTcS2izbDe/dRfbi5EDr2Uue3sz6+med3hjecZzrKJUX19wP1WwPifEOH2X/smzzGOdqlQtylMZQh3nNeho/GBwbDVXsXsR6LcDgoInDnw63cDV7n4dTs6giGmcx0knhDWH24Z/vrgNSqzbNY9hIgVBNWUqs/1o7/xrbK1HilYBPAiVO0F6+vJOpzdFrpEZVr0M++u+X2Zkt1sfshKZqt0O07KbH8h4xj3J+6iDF5RHHFGmZy0awFGZGIi8wqlffwQfZ+l7nPU1hpMD5DkArxBWJWgnquyCNpQ44OlmTpPRa/gopRpuMwJ1r6vDPhgIavJX6cKQ2lKTYKG2/HB+ZEl/IUtuXxKO7bFe4KOvjJpMwBjOmzqbn2sk3GqbSg8NfNMFA4FjRBvHXOaMsDCqz0MJxLFKvIfYRVWG8XAU6BU82RoS3qGFSOhI6N/DvD7dx1V40q52iWv2j4/S41P5zrtMqQm7wofocptz6sS7GLE1u9rPCBLRIck0wzi3OF7MV2p4wlw6lw=" + - ==: fr.azur.tcoww.utils.skins.WerewolfSkin + value: "ewogICJ0aW1lc3RhbXAiIDogMTYxNTYxMTkwOTY4MCwKICAicHJvZmlsZUlkIiA6ICIwMGM2Yjk0YTY5YmU0MzY3OTkwOTQxNjFjMjAxOWI3ZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJLQUVWRVJZIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2I0MGRjNTcxZGUwZGQ4ZmQ5NzBjNzNmOTE2NGJjMTQ0Njk1MWFlNDhkNWFiZTQyMzI5MGVlYjFhODc4NDU1ZmUiCiAgICB9CiAgfQp9" + signature: "kVGwx98YPc6tIZ306TiGI5eoK4v7oEjIvCaOPS03jq4LjBWV12NBTWW67u+HrI2/2m3r8pvAyx1Ddpw4YWyaDbaG0FvLuurWbETqtwvyvVx7R3BZHgw2EnVOYk4+WPmA8xUgzoIbZF/Ch4bSqP7UlZy7/fz4AQwFK/qLMzApOAeV4Kzn4p6+MK2uOkfSjGgwxqAO/+TZj6u01mk1NKNh4ors9RGDG3DBHZKSxTG/PzY5ErKABRXkB/RBMA5IvU5Rzn5cH+Sfkus/7LtYp5u+5i+HcpN/klyBBw4D5di3WzFOAIX78ZiyKzKzWpSN0z6Cb2DZdo1ufeZH9mw8nv+A8VfpGXwphwde+oGBP4l4OffE7YvbnWyVHmlG0L36iI2/FkWQl91GIT15YBHrjeQ9pmvbzCQUMyAHi2jZePTTcT1rDnSzBk7fc9IwfcBRNyqbveTNu9zikfx0W6GnXAbV4qOTIIVEHlpxQ9KW017sqmgiF5l/3ZVwqbEQzglNehYHA55vRfKY0HKbGB54k1oTnM3X7mNXIu6fk8dVgCvT8lVdDm3LWcE6aWF8Yp6QrXNvTNW1yxSRAhigsHrvbajp2Odg18lMTng0oh/4JiYOQAgb6tFdRtQ4nrSVHRBOEvY09IRFzVTTd7n2JaYZ6QcCMOiKOX25fv22rbjSeAZ/Whk=" + - ==: fr.azur.tcoww.utils.skins.WerewolfSkin + value: "ewogICJ0aW1lc3RhbXAiIDogMTc0Nzk4MDc5ODQyMywKICAicHJvZmlsZUlkIiA6ICI2NWI5NTU1YWQyMGU0NWM5YjFkNmU3MjQwNjU0NTBkNCIsCiAgInByb2ZpbGVOYW1lIiA6ICJKYXZhUHJvZmlsZU5hbWVYIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzJlZTlmNjcxYzFmNjY4Y2IwYWUwNGE5YzhiZWM0OTVlYTVmNzNmNTNmYmY3ZjM5MmNkYjdlMTc1ZmVjZDFjYmUiCiAgICB9CiAgfQp9" + signature: "wGc2rNbc7+nziEDMKFoBIltHZwx5PQfsfMGyRTfTUdtVi3O4iu0idcpTsTVJ80njIFZvmLpzlwjPu6ULrXJwgQQyGCNdp60jQMl9vGjzgJzs6uqhSCke3EvjOCuAGkv2ScRY5hDGQOnIruxwmgYgDeXHnujt+zTBvW+imxLVaZhXoKVPyqlvm6njWp0XECyAi8DFKbzIdDVp+NsRzIGjKeVoMgWd4xlNazUZGgTsXNCD/+aZOJ1LxA51I8Wgsm888MUXnaGhNI3U4jJNKHAPZMS4++JEuwWzlptJdZIa1jOfwMD6HvIPKEmC5+eDCRFvPIEh84VqErtNTPEUAz7wZAJvO+j+x5A/9VnQmKJhEBxBjlw1Ky+mQcLJnRX/x9jc4EvEd9gWGIUj46y3IF8jWn71eXvinSJ4Op4LQEiv5BfuyMTfY2xwFTlGWjdYF6Xnac+Gz6+E1gjCBSuqKWd56QFDcrqCcvbG50ERhenCUEhUgI33rXNxS/hwz2iClVM26GFJlUtZkZ7/021FjEQNLEYivI1ZkHe9ip8sxx2QVKd5k7Ui/hXkP4xSal3okL4Ar/cThMh0aoWzziYsoAahtoxFWEags7lNOffMoLGmPbgGVRUGHogNu2CES0SNs4AhHVUVERo8OTJHx46XJxXqvLzeEn6zXFD63XXQR8AyXTQ=" + - ==: fr.azur.tcoww.utils.skins.WerewolfSkin + value: "ewogICJ0aW1lc3RhbXAiIDogMTY0Mjc4ODk3NDg1NSwKICAicHJvZmlsZUlkIiA6ICIzYzE0YmVkNDFiOGE0MDIzOGM3MDgzMTA1NzEwMTZmYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJOb2Jpa28iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWZlNzIzMDdjZTEyNmI1Y2I0ZDQ0ZGFlZTcwZDI1ZmQwNDMwOGJjN2M0MzI4OWM3ZDk3MDY4NDY5NWI2MGJhIgogICAgfQogIH0KfQ==" + signature: "hJ/FhIMQY9G/BqOvGJ0nhuJk/7Y/q/unCpeC7LxGvcYjXzsY/kcInwUzgfjRqNI0oI5ggOAdxIiaGvBRqWCshjxcx6iRyJZBMKwFchM1baHntRl22yxvBA16gpMxbWTihQ0Jtz9m/Dj8clYgyEkMOKFEOya5YiyyqjK+YOl5xWiM1pGAomFixqr7VBLk/NE7e+qYXuFjDl3IZ1OP+tgdgyjkqUZE3OBGQfXP6wvTFjgk/maCPUmzffnbw/yH4JZIa3N/vhK+jzowcV+ymZK/9+10ge8hIZ5LZPdU90xLWd2zPYFjju/vr9TFWUG4YkV8l1vSsG7P8MYjMKFh/YQoTyyjJUZw9YGfnRENZrdegttUxefJywpBgp0xVt5vyAMM9XjTEtwK/A5gef0fD52lKWpwD6xamPBnhb8yRPUnncapGBrQvFhB8uQnkS8BKqtiJyz8XJHg8quzUXjYd+Ywn5p+lzP5zsDXQDYOfcm4FZGYp3oFwJZz1s4YOjP8Abjd+4v0sQIcP+Kj8lBzrADQSvTIJaQZO/emnpkZYoW/ggSJLa+BrRUXK5gNHdZzUI/EDOJggrGn3ezSLd96DyDlosG+lGM/EpuiB504YNzQfrm1scVbk9R4YHNhy+sau04DJcRY0p52qeaVDswMkfjUA6JBvBFT9SqQeB7q9qRwLrk=" + # The time in second before teleport no sleeping player -playerSleep: 20 \ No newline at end of file +player-sleep: 30 \ No newline at end of file diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml index c179695..d1072db 100644 --- a/src/main/resources/paper-plugin.yml +++ b/src/main/resources/paper-plugin.yml @@ -9,8 +9,9 @@ dependencies: server: SkinsRestorer: load: BEFORE - required: true + required: false join-classpath: true voicechat: load: BEFORE - required: true \ No newline at end of file + required: false + join-classpath: true \ No newline at end of file