Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore feature #22

Open
wants to merge 10 commits into
base: dev/dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/dev/mikchan/mcnp/chat/ChatPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import dev.mikchan.mcnp.chat.contract.formatting.IFormatter
import dev.mikchan.mcnp.chat.contract.keys.IKeys
import dev.mikchan.mcnp.chat.contract.log.IChatLogger
import dev.mikchan.mcnp.chat.contract.users.IUserManager
import dev.mikchan.mcnp.chat.contract.utility.IUtility
import org.bstats.bukkit.Metrics
import org.bukkit.plugin.java.JavaPlugin

Expand All @@ -28,6 +29,7 @@ class ChatPlugin : JavaPlugin() {
val eventManager: IEventManager by lazy { factory.createEventManager() }
val keys: IKeys by lazy { factory.createKeys() }
val chatLogger: IChatLogger by lazy { factory.createChatLogger() }
val utility: IUtility by lazy { factory.createUtility() }

override fun onEnable() {
commandManager.enableAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import dev.mikchan.mcnp.chat.contract.formatting.IFormatter
import dev.mikchan.mcnp.chat.contract.keys.IKeys
import dev.mikchan.mcnp.chat.contract.log.IChatLogger
import dev.mikchan.mcnp.chat.contract.users.IUserManager
import dev.mikchan.mcnp.chat.contract.utility.IUtility

/**
* An abstract factory
Expand Down Expand Up @@ -60,4 +61,11 @@ interface IChatPluginFactory {
* @return A new chat logger
*/
fun createChatLogger(): IChatLogger

/**
* Creates utility object
*
* @return A new utility object
*/
fun createUtility(): IUtility
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ class MCNChatEvent(
/**
* Set of recipients that this chat message will be displayed to.
*/
val recipients: Set<Player>,
var recipients: Set<Player>,

/**
* Is this message globally visible.
*
* If [dev.mikchan.mcnp.chat.config.IConfig.enableLocal] is `false`, this value is always `true`.
* If [dev.mikchan.mcnp.chat.contract.config.IConfig.enableLocal] is `false`, this value is always `true`.
*/
val isGlobal: Boolean,
var isGlobal: Boolean,

/**
* The raw message that the player is attempting to send.
*/
val message: String,
var message: String,

/**
* Fully formatted message.
*/
val formattedMessage: String,
var formattedMessage: String,

/**
* Is the message meant to be previewed in the secure chat thing (meh)
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/dev/mikchan/mcnp/chat/contract/keys/IKeys.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ interface IKeys {
* Namespaced key related to spy feature
*/
val spy: IKey<Byte>

/**
* Namespaced key related to ignore feature
*/
val ignore: IKey<ByteArray>
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,13 @@ interface IUserManager {
* @return The player object, if found. `null` if player is not found, not online, or [search] is not a valid UUID.
*/
fun findByUUID(search: String): Player?

/**
* Checks if [ignorer] ignores [ignored]
*
* @param ignorer The player who is ignoring
* @param ignored The player who is being ignored
* @return Is [ignorer] ignores [ignored]
*/
fun doesIgnore(ignorer: Player, ignored: Player): Boolean
}
40 changes: 40 additions & 0 deletions src/main/java/dev/mikchan/mcnp/chat/contract/utility/IUtility.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dev.mikchan.mcnp.chat.contract.utility

import java.util.*

/**
* A Utility interface
*/
interface IUtility {
/**
* Converts an [UUID] set to [ByteArray]
*
* @param uuids The set with UUIDs
* @return The resulting [ByteArray]
*/
fun uniqueIdSetToByteArray(uuids: Set<UUID>): ByteArray

/**
* Converts [ByteArray] to [UUID] set
*
* @param byteArray The [ByteArray]
* @return The resulting set
*/
fun byteArrayToUniqueIdSet(byteArray: ByteArray): Set<UUID>

/**
* Converts an [UUID] object to [ByteArray]
*
* @param uuid The [UUID] object
* @return The resulting [ByteArray]
*/
fun uniqueIdToByteArray(uuid: UUID): ByteArray

/**
* Converts a [ByteArray] to [UUID] object
*
* @param byteArray The [ByteArray]
* @return The resulting [UUID] object. If the [byteArray] is malformed, returns `null`.
*/
fun byteArrayToUniqueId(byteArray: ByteArray): UUID?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package dev.mikchan.mcnp.chat.implementation.base.commands

import dev.mikchan.mcnp.chat.ChatPlugin
import org.bukkit.ChatColor
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import java.util.*

internal abstract class BaseIgnoreCommand(private val plugin: ChatPlugin) : ICommand {
protected abstract fun processData(data: Set<UUID>, ignorePlayer: Player): Set<UUID>
protected abstract val ignorePhrase: String

override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
val player = sender as? Player

if (player == null) {
sender.sendMessage("${ChatColor.DARK_RED}This action is only accessible to players.")
return false
}

if (!player.hasPermission("mcn.chat.ignore")) {
sender.sendMessage("${ChatColor.DARK_RED}You have no permission to do that.")
return false
}

val ignorePlayerName = args.getOrNull(0)

if (ignorePlayerName == null) {
sender.sendMessage("${ChatColor.DARK_RED}The player name is not specified")
return false
}

val ignorePlayer = plugin.userManager.findByUsername(ignorePlayerName)

if (ignorePlayer == null) {
sender.sendMessage("${ChatColor.DARK_RED}The player '${ignorePlayerName}' is not found.")
return false
}

if (ignorePlayer == player) {
sender.sendMessage("${ChatColor.DARK_RED}You can't ignore yourself!")
return false
}

val bytes = player.persistentDataContainer.get(plugin.keys.ignore.key, plugin.keys.ignore.type) ?: ByteArray(0)
val data = processData(plugin.utility.byteArrayToUniqueIdSet(bytes), ignorePlayer)
player.persistentDataContainer.set(
plugin.keys.ignore.key,
plugin.keys.ignore.type,
plugin.utility.uniqueIdSetToByteArray(data)
)

sender.sendMessage("${ChatColor.DARK_GREEN}The player '$ignorePlayerName' $ignorePhrase!")

return true
}

override fun onTabComplete(
sender: CommandSender,
command: Command,
label: String,
args: Array<out String>
): MutableList<String>? {
return if (args.size == 1) null else mutableListOf()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import dev.mikchan.mcnp.chat.contract.formatting.IFormatter
import dev.mikchan.mcnp.chat.contract.keys.IKeys
import dev.mikchan.mcnp.chat.contract.log.IChatLogger
import dev.mikchan.mcnp.chat.contract.users.IUserManager
import dev.mikchan.mcnp.chat.contract.utility.IUtility
import dev.mikchan.mcnp.chat.implementation.boosted.config.BoostedYamlConfig
import dev.mikchan.mcnp.chat.implementation.fallback.config.FallbackConfig
import dev.mikchan.mcnp.chat.implementation.fallback.formatting.FallbackFormatter
Expand All @@ -18,6 +19,7 @@ import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands.SpigotV1m16p
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.events.SpigotV1m16p5EventManager
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.keys.SpigotV1m16p5Keys
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.users.SpigotV1m16p5UserManager
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.utility.SpigotV1m16p5Utility
import me.clip.placeholderapi.PlaceholderAPIPlugin
import java.io.File

Expand Down Expand Up @@ -63,4 +65,8 @@ internal open class SpigotV1m16p5ChatPluginFactory(private val plugin: ChatPlugi
override fun createChatLogger(): IChatLogger {
return FileChatLogger(plugin)
}

override fun createUtility(): IUtility {
return SpigotV1m16p5Utility()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands

import dev.mikchan.mcnp.chat.ChatPlugin
import dev.mikchan.mcnp.chat.implementation.base.commands.BaseCommandManager
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands.command.MsgCommand
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands.command.ReloadCommand
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands.command.ReplyCommand
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands.command.SpyCommand
import dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands.command.*

internal class SpigotV1m16p5CommandManager(chatPlugin: ChatPlugin) : BaseCommandManager(
chatPlugin,
Expand All @@ -15,6 +12,8 @@ internal class SpigotV1m16p5CommandManager(chatPlugin: ChatPlugin) : BaseCommand
"msg" to MsgCommand(plugin, messageHistory),
"reply" to ReplyCommand(plugin, messageHistory),
"spy" to SpyCommand(plugin),
"ignore" to IgnoreCommand(plugin),
"unignore" to UnignoreCommand(plugin),
)
},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands.command

import dev.mikchan.mcnp.chat.ChatPlugin
import dev.mikchan.mcnp.chat.implementation.base.commands.BaseIgnoreCommand
import org.bukkit.entity.Player
import java.util.*

internal class IgnoreCommand(plugin: ChatPlugin) : BaseIgnoreCommand(plugin) {
override fun processData(data: Set<UUID>, ignorePlayer: Player): Set<UUID> {
return data + ignorePlayer.uniqueId
}

override val ignorePhrase: String = "is now in the ignore list"
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal class MsgCommand(private val plugin: ChatPlugin, private val history: M
}

if (sender is Player) {
user.sendMessage(sender.uniqueId, formattedMessage)
if (!plugin.userManager.doesIgnore(user, sender)) user.sendMessage(sender.uniqueId, formattedMessage)
if (user != sender) sender.sendMessage(sender.uniqueId, formattedMessage)

plugin.chatLogger.logPrivate(sender, user, message)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.commands.command

import dev.mikchan.mcnp.chat.ChatPlugin
import dev.mikchan.mcnp.chat.implementation.base.commands.BaseIgnoreCommand
import org.bukkit.entity.Player
import java.util.*

internal class UnignoreCommand(plugin: ChatPlugin) : BaseIgnoreCommand(plugin) {
override fun processData(data: Set<UUID>, ignorePlayer: Player): Set<UUID> {
return data - ignorePlayer.uniqueId
}

override val ignorePhrase: String = "is now not in the ignore list"
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ internal class SpigotV1m16p5MCNCListener(private val plugin: ChatPlugin) : Liste
val spies = plugin.server.onlinePlayers
.filter { player -> !event.recipients.contains(player) }
.filter { player -> checkSpy(player) }
.filter { player -> !plugin.userManager.doesIgnore(player, event.sender) }
.toSet()

if (spies.isEmpty()) return@scheduleSyncDelayedTask
Expand All @@ -53,6 +54,11 @@ internal class SpigotV1m16p5MCNCListener(private val plugin: ChatPlugin) : Liste
}
}

@EventHandler(priority = EventPriority.LOWEST)
fun onMCNCFilterEvent(event: MCNChatEvent) {
event.recipients = event.recipients.filter { !plugin.userManager.doesIgnore(it, event.sender) }.toSet()
}

@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
fun onLogEvent(event: MCNChatEvent) {
if (event.isCancelled) return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import org.bukkit.persistence.PersistentDataType

internal class SpigotV1m16p5Keys(plugin: ChatPlugin) : IKeys {
override val spy = SpigotV1m16p5Key(plugin, "spy", PersistentDataType.BYTE)
override val ignore = SpigotV1m16p5Key(plugin, "ignore", PersistentDataType.BYTE_ARRAY)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,15 @@ internal class SpigotV1m16p5UserManager(private val plugin: ChatPlugin) : IUserM
null
}
}

override fun doesIgnore(ignorer: Player, ignored: Player): Boolean {
if (!ignored.hasPermission("mcn.chat.ignore")) return false
val ignoreList = plugin.utility.byteArrayToUniqueIdSet(
ignorer.persistentDataContainer.get(
plugin.keys.ignore.key,
plugin.keys.ignore.type
) ?: ByteArray(0)
)
return ignoreList.contains(ignored.uniqueId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package dev.mikchan.mcnp.chat.implementation.spigot.v1_16_5.utility

import dev.mikchan.mcnp.chat.contract.utility.IUtility
import java.nio.ByteBuffer
import java.util.*

internal class SpigotV1m16p5Utility : IUtility {
override fun uniqueIdSetToByteArray(uuids: Set<UUID>): ByteArray {
return uuids.flatMap { uniqueIdToByteArray(it).toList() }.toByteArray()
}

override fun byteArrayToUniqueIdSet(byteArray: ByteArray): Set<UUID> {
return byteArray.toList().chunked(16).mapNotNull { byteArrayToUniqueId(it.toByteArray()) }.toSet()
}

override fun uniqueIdToByteArray(uuid: UUID): ByteArray {
val buffer = ByteBuffer.wrap(ByteArray(16))
buffer.putLong(uuid.mostSignificantBits)
buffer.putLong(uuid.leastSignificantBits)
return buffer.array()
}

override fun byteArrayToUniqueId(byteArray: ByteArray): UUID? {
if (byteArray.size != 16) return null
val buffer = ByteBuffer.wrap(byteArray)
val high = buffer.getLong()
val low = buffer.getLong()
return UUID(high, low)
}
}
11 changes: 11 additions & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ commands:
permission: mcn.chat.spy
description: Enables spy feature

ignore:
permission: mcn.chat.ignore
description: Adds a player to the ignore list

unignore:
permission: mcn.chat.ignore
description: Removes a player from the ignore list

mcn_chat:
aliases:
- chat
Expand All @@ -53,6 +61,7 @@ permissions:
- mcn.chat.reply
- mcn.chat.global
- mcn.chat.local
- mcn.chat.ignore
mcn.chat.msg:
default: true
mcn.chat.reply:
Expand All @@ -61,6 +70,8 @@ permissions:
default: true
mcn.chat.local:
default: true
mcn.chat.ignore:
default: true

mcn.chat.colors:
default: op
Expand Down