Skip to content

Commit

Permalink
Add //signsearch
Browse files Browse the repository at this point in the history
  • Loading branch information
Nickster258 committed Jun 15, 2020
1 parent 3b9eaf9 commit e0054ea
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 36 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ common in redstoning.

NOTE: The order of arguments does not matter apart from `count` and `spacing`.

## `//find`
## `//find [mask]`
Search a selected region for a specific WorldEdit material mask.

## `//signsearch|//ss [regex]`
Search a selected region for signs that match a provided regex.

## `/container`
Gives the player a chest, barrel, hopper, or furnace with the proper amount of items to provide a signal strength of specified power.

Expand Down
38 changes: 4 additions & 34 deletions src/main/kotlin/Find.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,19 @@ import com.sk89q.worldedit.function.operation.Operations
import com.sk89q.worldedit.function.visitor.RegionVisitor
import com.sk89q.worldedit.math.BlockVector3
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException
import com.sk89q.worldedit.util.formatting.component.PaginationBox
import com.sk89q.worldedit.util.formatting.text.Component
import com.sk89q.worldedit.util.formatting.text.TextComponent
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent
import com.sk89q.worldedit.util.formatting.text.format.TextColor
import org.bukkit.ChatColor
import org.bukkit.entity.Player
import java.util.*
import kotlin.collections.HashMap
import kotlin.math.ceil

val findResults = HashMap<UUID, MutableList<BlockVector3>>()
const val MAKE_SELECTION_FIRST = "Make a region selection first."

@CommandAlias("/find")
@Description("Find some shid in selecton")
@CommandPermission("redstonetools.find")
class Find(private val worldEdit: WorldEdit) : BaseCommand() {

@Default
@CommandCompletion("@find_mask")
@CommandCompletion("@we_mask")
@Syntax("[material]")
fun find(
player: Player,
Expand All @@ -45,15 +36,15 @@ class Find(private val worldEdit: WorldEdit) : BaseCommand() {
doFind(BukkitAdapter.adapt(player), arg)
}

@Subcommand("page")
@Subcommand("-p")
@CommandCompletion("@find_page")
@Syntax("[number]")
fun page(
player: Player,
page: Int
) {
val locations = findResults[player.uniqueId] ?: throw RedstoneToolsException(MAKE_SELECTION_FIRST)
val paginationBox = FindPaginationBox(locations, "Results", "//find page %page%")
val paginationBox = LocationsPaginationBox(locations, "Find Results", "//find -p %page%")
val component = try {
paginationBox.create(page)
} catch (e: InvalidComponentException) {
Expand Down Expand Up @@ -87,32 +78,11 @@ class Find(private val worldEdit: WorldEdit) : BaseCommand() {
}
}

class FindPaginationBox(private val locations: MutableList<BlockVector3>, title: String, command: String) :
PaginationBox("${ChatColor.LIGHT_PURPLE}$title", command) {
override fun getComponent(number: Int): Component {
if (number > locations.size) throw IllegalArgumentException("Invalid location index.")
return TextComponent.of("${number}: ${locations[number]}")
.color(TextColor.LIGHT_PURPLE)
.clickEvent(ClickEvent.runCommand("/tp ${locations[number].x} ${locations[number].y} ${locations[number].z}"))
.hoverEvent(HoverEvent.showText(TextComponent.of("Click to teleport")))
}

override fun getComponentsSize(): Int = locations.size
}

class FindPageCompletionHandler :
CommandCompletions.CommandCompletionHandler<BukkitCommandCompletionContext> {
override fun getCompletions(context: BukkitCommandCompletionContext): Collection<String> {
val player = context.sender as Player
val locations = findResults[player.uniqueId] ?: return emptyList()
return (1..ceil(locations.size / 8f).toInt()).map { it.toString() }.toList()
return (1..ceil(locations.size / 7f).toInt()).map { it.toString() }.toList()
}
}

class FindCompletionHandler(worldEdit: WorldEdit) :
CommandCompletions.CommandCompletionHandler<BukkitCommandCompletionContext> {
private val maskFactory = MaskFactory(worldEdit)
override fun getCompletions(context: BukkitCommandCompletionContext): Collection<String> {
return maskFactory.getSuggestions(context.input)
}
}
47 changes: 46 additions & 1 deletion src/main/kotlin/RedstoneTools.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
package redstonetools

import co.aikar.commands.*
import com.sk89q.worldedit.WorldEdit
import com.sk89q.worldedit.bukkit.WorldEditPlugin
import com.sk89q.worldedit.extension.factory.MaskFactory
import com.sk89q.worldedit.math.BlockVector3
import com.sk89q.worldedit.util.formatting.component.PaginationBox
import com.sk89q.worldedit.util.formatting.text.Component
import com.sk89q.worldedit.util.formatting.text.TextComponent
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent
import com.sk89q.worldedit.util.formatting.text.format.TextColor
import org.bukkit.ChatColor
import org.bukkit.Material
import org.bukkit.plugin.java.JavaPlugin
import java.util.logging.Level

const val MAKE_SELECTION_FIRST = "Make a region selection first."

class RedstoneTools : JavaPlugin() {

private fun handleCommandException(
Expand Down Expand Up @@ -37,14 +48,16 @@ class RedstoneTools : JavaPlugin() {
server.pluginManager.registerEvents(WorldEditHelper(this, worldEdit), this)
PaperCommandManager(this).apply {
commandCompletions.registerCompletion("slabs", SlabCompletionHandler())
commandCompletions.registerCompletion("find_mask", FindCompletionHandler(worldEdit))
commandCompletions.registerCompletion("we_mask", MaskCompletionHandler(worldEdit))
commandCompletions.registerCompletion("find_page", FindPageCompletionHandler())
commandCompletions.registerCompletion("search_page", SearchPageCompletionHandler())
registerThing<SignalStrength>("Signal strength", { SignalStrength.of(it) }, SignalStrength.values)
registerThing<SignalContainer>("Container", { SignalContainer.of(it) }, SignalContainer.values)
setDefaultExceptionHandler(::handleCommandException, false)
registerCommands(
RStack(worldEdit),
Find(worldEdit),
SignSearch(worldEdit),
Container(),
Slab()
)
Expand Down Expand Up @@ -108,3 +121,35 @@ class SignalContainer(val material: Material) {
}
}
}

class MaskCompletionHandler(worldEdit: WorldEdit) :
CommandCompletions.CommandCompletionHandler<BukkitCommandCompletionContext> {
private val maskFactory = MaskFactory(worldEdit)
override fun getCompletions(context: BukkitCommandCompletionContext): Collection<String> {
return maskFactory.getSuggestions(context.input)
}
}

class LocationsPaginationBox(private val locations: MutableList<BlockVector3>, title: String, command: String) :
PaginationBox("${ChatColor.LIGHT_PURPLE}$title", command) {

init {
setComponentsPerPage(7)
}

override fun getComponent(number: Int): Component {
if (number > locations.size) throw IllegalArgumentException("Invalid location index.")
return TextComponent.of("${number+1}: ${locations[number]}")
.color(TextColor.LIGHT_PURPLE)
.clickEvent(ClickEvent.runCommand("/tp ${locations[number].x} ${locations[number].y} ${locations[number].z}"))
.hoverEvent(HoverEvent.showText(TextComponent.of("Click to teleport")))
}

override fun getComponentsSize(): Int = locations.size

override fun create(page: Int): Component {
super.getContents().append(TextComponent.of("Total Results: ${locations.size}").color(TextColor.GRAY))
.append(TextComponent.newline())
return super.create(page)
}
}
109 changes: 109 additions & 0 deletions src/main/kotlin/SignSearch.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package redstonetools

import co.aikar.commands.BaseCommand
import co.aikar.commands.BukkitCommandCompletionContext
import co.aikar.commands.CommandCompletions
import co.aikar.commands.annotation.*
import com.sk89q.jnbt.StringTag
import com.sk89q.worldedit.IncompleteRegionException
import com.sk89q.worldedit.WorldEdit
import com.sk89q.worldedit.bukkit.BukkitAdapter
import com.sk89q.worldedit.function.RegionFunction
import com.sk89q.worldedit.function.RegionMaskingFilter
import com.sk89q.worldedit.function.mask.BlockCategoryMask
import com.sk89q.worldedit.function.operation.Operations
import com.sk89q.worldedit.function.visitor.RegionVisitor
import com.sk89q.worldedit.math.BlockVector3
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException
import com.sk89q.worldedit.util.formatting.text.TextComponent
import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer
import com.sk89q.worldedit.world.block.BlockCategories
import org.bukkit.entity.Player
import java.util.*
import kotlin.collections.HashMap
import kotlin.math.ceil

val searchResults = HashMap<UUID, MutableList<BlockVector3>>()

@CommandAlias("/signsearch|/ss")
@Description("Search for text of signs within a selection using a regular expression")
@CommandPermission("redstonetools.signsearch")
class SignSearch(private val worldEdit: WorldEdit) : BaseCommand() {
@Default
@Syntax("[expression]")
fun search(
player: Player,
arg: String
) {
doSearch(BukkitAdapter.adapt(player), arg)
}

@Subcommand("-p")
@CommandCompletion("@search_page")
@Syntax("[number]")
fun page(
player: Player,
page: Int
) {
val locations = searchResults[player.uniqueId] ?: throw RedstoneToolsException(MAKE_SELECTION_FIRST)
val paginationBox = LocationsPaginationBox(locations, "Search Results", "//signsearch -p %page%")
val component = try {
paginationBox.create(page)
} catch (e: InvalidComponentException) {
throw RedstoneToolsException("Invalid page number.")
}
BukkitAdapter.adapt(player).print(component)
}

private fun doSearch(player: WEPlayer, arg: String) {
val pattern = try {
Regex(arg)
} catch (e: Exception) {
throw RedstoneToolsException("Illegal pattern: " + e.message)
}
val session = worldEdit.sessionManager.get(player)
val selection = try {
session.getSelection(session.selectionWorld)
} catch (e: IncompleteRegionException) {
throw RedstoneToolsException(MAKE_SELECTION_FIRST)
}
val matches = mutableListOf<BlockVector3>()
val blockMask = BlockCategoryMask(session.selectionWorld, BlockCategories.SIGNS)
val regionFunction = RegionFunction { position ->
val baseBlock = session.selectionWorld.getFullBlock(position)
if (baseBlock.hasNbtData()) {
val compoundTag = baseBlock.nbtData!!
val content = buildString {
for (i in 1..4) {
val textTag = compoundTag.value["Text$i"] as StringTag
val component = GsonComponentSerializer.INSTANCE.deserialize(textTag.value) as TextComponent
append(component.getAllContent())
}
}
if (content.contains(pattern)) {
matches.add(position)
}
}
false
}
val regionMaskingFilter = RegionMaskingFilter(blockMask, regionFunction)
val regionVisitor = RegionVisitor(selection, regionMaskingFilter)
Operations.complete(regionVisitor)
if (matches.isNotEmpty()) {
searchResults[player.uniqueId] = matches
page(BukkitAdapter.adapt(player), 1)
} else {
searchResults.remove(player.uniqueId)
player.printInfo(TextComponent.of("No results found."))
}
}
}

class SearchPageCompletionHandler :
CommandCompletions.CommandCompletionHandler<BukkitCommandCompletionContext> {
override fun getCompletions(context: BukkitCommandCompletionContext): Collection<String> {
val player = context.sender as Player
val locations = searchResults[player.uniqueId] ?: return emptyList()
return (1..ceil(locations.size / 7f).toInt()).map { it.toString() }.toList()
}
}
13 changes: 13 additions & 0 deletions src/main/kotlin/Util.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package redstonetools

import com.sk89q.worldedit.util.formatting.text.TextComponent

fun TextComponent.getAllContent(): String {
return if (this.children().isEmpty()) {
this.content()
} else {
this.children().filterIsInstance<TextComponent>().joinToString(separator = "") { textComponent ->
textComponent.getAllContent()
}
}
}

0 comments on commit e0054ea

Please sign in to comment.