Add Backup, (Broken)Discord integration and some OP items. Fix some small bugs

This commit is contained in:
Julius 2019-08-27 15:10:01 +02:00
parent 4a0c14197a
commit 845f561969
18 changed files with 516 additions and 41 deletions

View file

@ -1,10 +1,3 @@
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm'
id 'com.github.johnrengelman.shadow'
id 'net.minecrell.plugin-yml.bukkit'
}
dependencies { dependencies {
compileOnly project(":VoidPlugin") compileOnly project(":VoidPlugin")
} }

24
VoidBackup/build.gradle Normal file
View file

@ -0,0 +1,24 @@
dependencies {
compileOnly project(":VoidPlugin")
implementation 'com.github.luben:zstd-jni:1.4.3-1'
implementation 'org.kamranzafar:jtar:2.3'
}
bukkit {
main = "nl.voidcorp.backupplugin.VoidBackup"
apiVersion = '1.14'
author = 'J00LZ'
depend = ['VoidPlugin']
commands {
'force-backup' {
description = "Guess what..."
permission = "backup.force"
}
}
permissions{
'backup.force'{
description = "Allows forcing backups"
setDefault("OP")
}
}
}

View file

@ -0,0 +1,133 @@
package nl.voidcorp.backupplugin
import com.github.luben.zstd.ZstdOutputStream
import nl.voidcorp.mainplugin.CommandHandler
import nl.voidcorp.mainplugin.VoidPluginBase
import nl.voidcorp.mainplugin.adapter
import nl.voidcorp.mainplugin.commands.VoidCommand
import nl.voidcorp.mainplugin.messaging.Message
import nl.voidcorp.mainplugin.messaging.MessageType
import nl.voidcorp.mainplugin.moshi
import org.bukkit.Bukkit
import org.bukkit.command.Command
import org.bukkit.command.CommandSender
import org.bukkit.scheduler.BukkitRunnable
import org.joda.time.DateTime
import org.joda.time.format.ISODateTimeFormat
import org.kamranzafar.jtar.TarEntry
import org.kamranzafar.jtar.TarOutputStream
import java.io.File
import java.nio.file.Files
import java.util.*
import kotlin.concurrent.thread
import kotlin.math.ln
import kotlin.math.pow
import kotlin.streams.toList
class VoidBackup(override val comment: String = "Make Backups!") : VoidPluginBase() {
private val backupDir = File(server.worldContainer, "backups").apply {
if (!exists()) mkdirs()
}
private val backupTask = BackupTask(this)
lateinit var conf: Config
override fun enable() {
send("VoidPlugin", MessageType.GET_CONFIG)
send("VoidPlugin", MessageType.POST_CONFIG, moshi.adapter<Config>().toJson(conf))
backupTask.runTaskTimer(this, 20, conf.timeoutMinutes * 60 * 20)
CommandHandler(this).registerCommand("force-backup", ForceBackupCommand(this))
}
override fun disable() {
backupTask.cancel()
}
override fun recieve(message: Message) {
if (message.messageType == MessageType.GET_CONFIG) {
conf = moshi.adapter<Config>().fromJson(message.content)!!
}
}
fun backup() {
Bukkit.broadcastMessage("Backing up. Server may lag for a bit...")
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-off")
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-all")
val done = mutableListOf<UUID>()
server.worlds.forEach { world ->
val dir = world.worldFolder
val whereTo = createTempFile("yeet")
val whereToZ = File(
backupDir,
"${world.name}-${DateTime.now().toString(ISODateTimeFormat.basicDateTimeNoMillis())}.tar.zst"
)
thread {
val files = Files.walk(dir.toPath()).map { it.toFile() }.filter { !it.isDirectory }.toList()
val tar = TarOutputStream(whereTo)
tar.use { tarOS ->
for (f in files) {
tarOS.putNextEntry(TarEntry(f, f.path.removePrefix(".${File.separatorChar}")))
f.inputStream().use {
it.copyTo(tarOS)
}
}
}
val zstOutputStream = ZstdOutputStream(whereToZ.outputStream())
val inp = whereTo.inputStream()
zstOutputStream.use { zst ->
inp.use { tr ->
tr.copyTo(zst)
}
}
Bukkit.broadcastMessage("World ${world.name} has been saved, it is ${humanReadableByteCount(whereToZ.length())}")
done.add(world.uid)
if (server.worlds.size == done.size) {
Bukkit.getScheduler().runTask(this, EnableSave)
}
}
}
}
private fun humanReadableByteCount(bytes: Long, si: Boolean = false): String {
val unit = if (si) 1000 else 1024
if (bytes < unit) return "$bytes B"
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
}
object EnableSave : Runnable {
override fun run() {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-on")
}
}
class BackupTask(private val pl: VoidBackup) : BukkitRunnable() {
override fun run() {
pl.backup()
}
}
data class Config(val timeoutMinutes: Long = 30)
class ForceBackupCommand(private val pl: VoidBackup) : VoidCommand() {
override fun onCommand(
sender: CommandSender,
command: Command,
label: String,
args: Array<out String>
): Boolean {
pl.backup()
return true
}
}
}

View file

@ -1,9 +1,3 @@
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm'
id 'com.github.johnrengelman.shadow'
id 'net.minecrell.plugin-yml.bukkit'
}
dependencies { dependencies {
compileOnly project(":VoidPlugin") compileOnly project(":VoidPlugin")

View file

@ -12,10 +12,20 @@ import nl.voidcorp.mainplugin.messaging.MessageType
import nl.voidcorp.mainplugin.moshi import nl.voidcorp.mainplugin.moshi
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.attribute.Attribute
import org.bukkit.attribute.AttributeModifier
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.HumanEntity
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.inventory.ClickType import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.CraftItemEvent
import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack import org.bukkit.event.player.PlayerAttemptPickupItemEvent
import org.bukkit.inventory.*
import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.transaction
import java.util.logging.Logger import java.util.logging.Logger
@ -23,6 +33,8 @@ import kotlin.math.min
class VoidBank(override val comment: String = "Sell all the diamonds!") : VoidPluginBase() { class VoidBank(override val comment: String = "Sell all the diamonds!") : VoidPluginBase() {
private val title = "Exchange" private val title = "Exchange"
override fun enable() { override fun enable() {
VoidBank.logger = logger VoidBank.logger = logger
@ -47,8 +59,11 @@ class VoidBank(override val comment: String = "Sell all the diamonds!") : VoidPl
for (iconMenu in iconMenus) { for (iconMenu in iconMenus) {
server.pluginManager.registerEvents(iconMenu, this) server.pluginManager.registerEvents(iconMenu, this)
} }
} }
override fun recieve(message: Message) { override fun recieve(message: Message) {
when (message.messageType) { when (message.messageType) {
MessageType.GET_CONFIG -> { MessageType.GET_CONFIG -> {
@ -182,5 +197,4 @@ class VoidBank(override val comment: String = "Sell all the diamonds!") : VoidPl
lateinit var logger: Logger lateinit var logger: Logger
lateinit var config: BankConfig lateinit var config: BankConfig
} }
} }

15
VoidCord/build.gradle Normal file
View file

@ -0,0 +1,15 @@
dependencies {
compileOnly project(":VoidPlugin")
implementation('net.dv8tion:JDA:4.0.0_45') {
exclude module: 'opus-java'
exclude group: 'org.jetbrains', module: 'annotations'
}
implementation 'khttp:khttp:1.0.0'
}
bukkit {
main = "nl.voidcorp.cordplugin.VoidCord"
apiVersion = '1.14'
author = 'J00LZ'
depend = ['VoidPlugin']
}

View file

@ -0,0 +1,3 @@
package nl.voidcorp.cordplugin
data class DiscordConfig(val botToken: String = "", val commandString: String = ",", val channels: MutableList<Long> = mutableListOf())

View file

@ -0,0 +1,112 @@
package nl.voidcorp.cordplugin
import khttp.get
import net.dv8tion.jda.api.JDA
import net.dv8tion.jda.api.JDABuilder
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter
import nl.voidcorp.mainplugin.VoidPluginBase
import nl.voidcorp.mainplugin.adapter
import nl.voidcorp.mainplugin.messaging.Message
import nl.voidcorp.mainplugin.messaging.MessageType
import nl.voidcorp.mainplugin.moshi
import org.bukkit.Bukkit
import org.bukkit.ChatColor
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.player.AsyncPlayerChatEvent
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
class VoidCord(override val comment: String = "Chat with Discord!") : VoidPluginBase() {
lateinit var conf: DiscordConfig
lateinit var jda: JDA
override fun enable() {
send("VoidPlugin", MessageType.GET_CONFIG)
send("VoidPlugin", MessageType.POST_CONFIG, moshi.adapter<DiscordConfig>().toJson(conf))
if (conf.botToken.isBlank()) {
logger.warning("Please add a bot token to the config, I can't send messages to discord without...")
this.disable()
return
}
jda = JDABuilder(conf.botToken).addEventListeners(EventManager(conf)).build()
server.pluginManager.registerEvents(ChatMapper(jda, conf), this)
}
class ChatMapper(val jda: JDA, val conf: DiscordConfig) : Listener {
@EventHandler(priority = EventPriority.MONITOR)
fun onChat(evt: AsyncPlayerChatEvent) {
val msg = evt.message
if (msg.startsWith("/")) {
return
} else {
val channels = conf.channels.map { jda.getTextChannelById(it) }.filterNotNull()
channels.forEach {
it.sendMessage("(Minecraft) ${evt.player.displayName}: $msg").queue()
}
}
}
@EventHandler(priority = EventPriority.MONITOR)
fun onJoin(evt: PlayerJoinEvent) {
val msg = "${evt.player.displayName} Joined!"
val channels = conf.channels.map { jda.getTextChannelById(it) }.filterNotNull()
channels.forEach {
it.sendMessage("(Minecraft) $msg").queue()
}
}
@EventHandler(priority = EventPriority.MONITOR)
fun onLeave(evt: PlayerQuitEvent) {
val msg = "${evt.player.displayName} Left!"
val channels = conf.channels.map { jda.getTextChannelById(it) }.filterNotNull()
channels.forEach {
it.sendMessage("(Minecraft) $msg").queue()
}
}
}
override fun disable() {
jda.shutdown()
}
override fun recieve(message: Message) {
when (message.messageType) {
MessageType.GET_CONFIG -> {
conf = moshi.adapter<DiscordConfig>().fromJson(message.content)!!
}
else -> Unit
}
}
class EventManager(private val config: DiscordConfig) : ListenerAdapter() {
private val italics = "(_.*_)|(\\*.*\\*)".toRegex()
private val bold = "(\\*\\*.*\\*\\*)".toRegex()
private val underline = "(__.*__)".toRegex()
private val strikethrough = "(~~.*~~)".toRegex()
override fun onGuildMessageReceived(event: GuildMessageReceivedEvent) {
if (event.author.idLong == event.jda.selfUser.idLong) return
if (event.channel.idLong in config.channels) {
val disc = event.message.contentDisplay
.replace(strikethrough) {
ChatColor.STRIKETHROUGH.toString() + it.groupValues[0].removeSurrounding("~~") + ChatColor.RESET.toString()
}
.replace(underline) {
ChatColor.UNDERLINE.toString() + it.groupValues[0].removeSurrounding("__") + ChatColor.RESET.toString()
}
.replace(bold) {
ChatColor.BOLD.toString() + it.groupValues[0].removeSurrounding("**") + ChatColor.RESET.toString()
}
.replace(italics) {
ChatColor.ITALIC.toString() + it.groupValues[0].removeSurrounding("_").removeSurrounding("*") + ChatColor.RESET.toString()
}
Bukkit.broadcastMessage("<${ChatColor.BLUE}${event.member!!.effectiveName}${ChatColor.RESET}>: $disc")
}
}
}
}

11
VoidOp/build.gradle Normal file
View file

@ -0,0 +1,11 @@
dependencies {
compileOnly project(":VoidPlugin")
}
bukkit {
main = "nl.voidcorp.opplugin.VoidOP"
apiVersion = '1.14'
author = 'J00LZ'
depend = ['VoidPlugin']
}

View file

@ -0,0 +1,12 @@
package nl.voidcorp.opplugin
import org.jetbrains.exposed.dao.EntityID
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
class StageKeeper(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<StageKeeper>(StageKeepers)
var stage by StageKeepers.stage
var player by StageKeepers.player
}

View file

@ -0,0 +1,8 @@
package nl.voidcorp.opplugin
import org.jetbrains.exposed.dao.IntIdTable
object StageKeepers : IntIdTable() {
val stage = enumeration("stage", VoidOp.Stage::class)
val player = uuid("player")
}

View file

@ -0,0 +1,171 @@
package nl.voidcorp.opplugin
import com.destroystokyo.paper.event.block.BeaconEffectEvent
import nl.voidcorp.mainplugin.VoidPluginBase
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.attribute.Attribute
import org.bukkit.attribute.AttributeModifier
import org.bukkit.block.Beacon
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.inventory.CraftItemEvent
import org.bukkit.event.player.PlayerAttemptPickupItemEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.*
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction
class VoidOp(override val comment: String = "Make everyone very op...") : VoidPluginBase() {
val maxistar = ItemStack(Material.NETHER_STAR).apply {
amount = 1
addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 1)
val meta = itemMeta
meta.setDisplayName("MaxiStar")
meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_UNBREAKABLE)
itemMeta = meta
}
val brokenBeacon = ItemStack(Material.COAL_BLOCK).apply {
val meta = itemMeta
meta.setDisplayName("Broken Beacon")
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE)
meta.addEnchant(Enchantment.ARROW_INFINITE, 100, true)
meta.lore = mutableListOf("Hmm...", "Maybe you should not have put it in the Blast Furnace...")
itemMeta = meta
}
val metaGem = ItemStack(Material.EMERALD).apply {
val meta = itemMeta
meta.setDisplayName("MetaGem")
meta.addAttributeModifier(
Attribute.GENERIC_ATTACK_DAMAGE,
AttributeModifier("Damage++", 100.0, AttributeModifier.Operation.ADD_NUMBER)
)
}
override fun enable() {
val recipe = ShapedRecipe(NamespacedKey(this, "maxi_recipe"), maxistar).shape("nnn", "nnn", "nnn")
.setIngredient('n', Material.NETHER_STAR)
Bukkit.addRecipe(recipe)
val brokenBeaconRecipe =
BlastingRecipe(NamespacedKey(this, "beacon_recipe"), brokenBeacon, Material.BEACON, 1.0f, 1000)
Bukkit.addRecipe(brokenBeaconRecipe)
server.pluginManager.registerEvents(ListenStuff(this), this)
transaction {
SchemaUtils.createMissingTablesAndColumns(StageKeepers)
}
}
override fun disable() {
val iter = Bukkit.recipeIterator()
while (iter.hasNext()) {
val it = iter.next()
if (it.result in listOf(maxistar, brokenBeacon, metaGem)) {
iter.remove()
}
}
}
class ListenStuff(private val bank: VoidOp) : Listener {
@EventHandler
fun blockPlace(evt: BlockPlaceEvent) {
if (evt.itemInHand in mutableListOf(bank.maxistar, bank.metaGem, bank.brokenBeacon)) {
evt.isCancelled = true
}
}
@EventHandler
fun itemPickup(evt: PlayerAttemptPickupItemEvent) {
setStage(evt.player, evt.item.itemStack)
}
@EventHandler
fun craftItem(evt: CraftItemEvent) {
if (evt.whoClicked is Player)
setStage(evt.whoClicked as Player, evt.recipe.result)
}
@EventHandler
fun blockOpen(evt: PlayerInteractEvent) {
if (evt.hasBlock()) {
val bl = evt.clickedBlock!!
if (bl is Beacon) {
if (bl.tier == 4)
}
}
}
private fun setStage(player: Player, itemStack: ItemStack) {
transaction {
val stageKeeper =
StageKeeper.find { StageKeepers.player eq player.uniqueId }.firstOrNull() ?: StageKeeper.new {
this.player = player.uniqueId
this.stage = Stage.PRE
}
var stageChanged = false
when (stageKeeper.stage) {
Stage.PRE -> {
val adv = Bukkit.getAdvancement(NamespacedKey.minecraft("nether/summon_wither"))!!
val a = player.getAdvancementProgress(adv)
if (a.isDone && itemStack.type == Material.NETHER_STAR) {
stageKeeper.stage = Stage.WITHER
stageChanged = true
}
}
Stage.WITHER -> TODO()
Stage.BEACON -> TODO()
Stage.MAXI -> TODO()
Stage.BROKEN -> TODO()
Stage.GOD -> TODO()
}
if (stageChanged) {
when (stageKeeper.stage) {
Stage.PRE -> TODO()
Stage.WITHER -> TODO()
Stage.BEACON -> TODO()
Stage.MAXI -> TODO()
Stage.BROKEN -> TODO()
Stage.GOD -> TODO()
}
}
}
}
}
class ItemStackChoice(private val itemStack1: ItemStack) : RecipeChoice {
override fun getItemStack(): ItemStack {
return itemStack1
}
override fun clone(): RecipeChoice {
return ItemStackChoice(itemStack1)
}
override fun test(itemStack: ItemStack): Boolean {
return itemStack == itemStack1
}
}
enum class Stage {
PRE,
WITHER,
BEACON,
MAXI,
BROKEN,
GOD
}
}

View file

@ -1,11 +1,3 @@
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm'
id 'com.github.johnrengelman.shadow'
id 'net.minecrell.plugin-yml.bukkit'
}
dependencies { dependencies {
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8" api "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
api 'org.jetbrains.exposed:exposed:0.17.1' api 'org.jetbrains.exposed:exposed:0.17.1'

View file

@ -2,9 +2,8 @@ package nl.voidcorp.mainplugin
import nl.voidcorp.mainplugin.messaging.Message import nl.voidcorp.mainplugin.messaging.Message
import nl.voidcorp.mainplugin.messaging.MessageType import nl.voidcorp.mainplugin.messaging.MessageType
import okio.Okio
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction
import java.io.File import java.io.File
class VoidPlugin( class VoidPlugin(
@ -22,6 +21,7 @@ class VoidPlugin(
conf.databaseUrl, conf.databaseUrl,
driver = conf.driver driver = conf.driver
) )
} }
override fun disable() { override fun disable() {
@ -49,6 +49,10 @@ class VoidPlugin(
logger.info(config.path) logger.info(config.path)
if (!config.exists()) { if (!config.exists()) {
config.createNewFile() config.createNewFile()
config.bufferedWriter().apply {
write("{}")
close()
}
return "{}" return "{}"
} }
return config.readText() return config.readText()

View file

@ -1,10 +1,3 @@
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm'
id 'com.github.johnrengelman.shadow'
id 'net.minecrell.plugin-yml.bukkit'
}
dependencies { dependencies {
compileOnly project(":VoidPlugin") compileOnly project(":VoidPlugin")
} }

View file

@ -1,10 +1,3 @@
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm'
id 'com.github.johnrengelman.shadow'
id 'net.minecrell.plugin-yml.bukkit'
}
dependencies { dependencies {
compileOnly project(":VoidPlugin") compileOnly project(":VoidPlugin")
} }

View file

@ -1,5 +1,5 @@
plugins { plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.41' apply false id 'org.jetbrains.kotlin.jvm' version '1.3.50' apply false
id 'com.github.johnrengelman.shadow' version '5.1.0' apply false id 'com.github.johnrengelman.shadow' version '5.1.0' apply false
id 'net.minecrell.plugin-yml.bukkit' version '0.3.0' apply false id 'net.minecrell.plugin-yml.bukkit' version '0.3.0' apply false
} }

View file

@ -5,3 +5,6 @@ include 'VoidPlugin'
include 'VoidAdmin' include 'VoidAdmin'
include 'VoidUtils' include 'VoidUtils'
include 'VoidBank' include 'VoidBank'
include 'VoidCord'
include 'VoidBackup'
include 'VoidOp'