mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-25 06:50:09 +08:00
[console] EndUserReadme
This commit is contained in:
parent
3763996590
commit
d9e3045d65
mirai-console/backend
integration-test/src
mirai-console
build.gradle.kts
compatibility-validation/jvm/api
resources/net/mamoe/mirai/console/internal/enduserreadme
src
@ -54,6 +54,7 @@ internal fun main() {
|
||||
error("Don't launch IntegrationTestBootstrap directly. See /test/MiraiConsoleIntegrationTestBootstrap.kt")
|
||||
}
|
||||
}
|
||||
System.setProperty("mirai.console.skip-end-user-readme", "")
|
||||
// @context: env.testunit = true
|
||||
// @context: env.inJUnitProcess = false
|
||||
// @context: env.exitProcessSafety = true
|
||||
|
@ -103,6 +103,10 @@ tasks {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
this.jvmArgs("-Dmirai.console.skip-end-user-readme")
|
||||
}
|
||||
|
||||
tasks.getByName("compileKotlin").dependsOn(
|
||||
DependencyDumper.registerDumpTaskKtSrc(
|
||||
project,
|
||||
|
@ -1287,6 +1287,29 @@ public final class net/mamoe/mirai/console/data/java/JavaAutoSavePluginData$Comp
|
||||
public final fun createKType (Ljava/lang/Class;[Lkotlin/reflect/KType;)Lkotlin/reflect/KType;
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/console/enduserreadme/EndUserReadme {
|
||||
public static final field Companion Lnet/mamoe/mirai/console/enduserreadme/EndUserReadme$Companion;
|
||||
public static final field DELAY Ljava/lang/String;
|
||||
public static final field PAUSE Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
public final fun put (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
|
||||
public final fun putAll (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/console/enduserreadme/EndUserReadme$Companion {
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/console/enduserreadme/EndUserReadme$Render {
|
||||
public fun <init> ()V
|
||||
public final fun delay ()V
|
||||
public final fun delay (I)V
|
||||
public final fun msg (Ljava/lang/String;)V
|
||||
public final fun pause ()V
|
||||
public final fun plusAssign (Ljava/lang/String;)V
|
||||
public final fun render ()Ljava/lang/String;
|
||||
public final fun unaryPlus (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public abstract class net/mamoe/mirai/console/events/AutoLoginEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/console/events/ConsoleEvent, net/mamoe/mirai/event/events/BotEvent {
|
||||
}
|
||||
|
||||
@ -1302,6 +1325,10 @@ public final class net/mamoe/mirai/console/events/AutoLoginEvent$Success : net/m
|
||||
public abstract interface class net/mamoe/mirai/console/events/ConsoleEvent : net/mamoe/mirai/event/Event {
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/console/events/EndUserReadmeInitializeEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/console/events/ConsoleEvent {
|
||||
public final fun getReadme ()Lnet/mamoe/mirai/console/enduserreadme/EndUserReadme;
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/console/events/StartupEvent : net/mamoe/mirai/event/AbstractEvent, net/mamoe/mirai/console/events/ConsoleEvent {
|
||||
public final fun getTimestamp ()J
|
||||
}
|
||||
|
@ -0,0 +1,129 @@
|
||||
::mirai-console.greeting
|
||||
|
||||
欢迎使用 mirai-console。
|
||||
在您正式开始使用 mirai-console 前,您需要完整阅读此用户须知。
|
||||
|
||||
此用户须知包含 mirai-console 本体及其所安装的插件的用户须知。
|
||||
当相关的最终用户须知更新时,mirai-console 只会显示已更新部分,而不会重新完整显示整个用户须知。
|
||||
|
||||
::mirai-console.usage
|
||||
|
||||
在使用 mirai-console 前,您需要完整阅读用户手册。
|
||||
<delay>2
|
||||
用户手册地址:
|
||||
GitHub: https://github.com/mamoe/mirai/blob/dev/docs/UserManual.md
|
||||
VuePress: https://docs.mirai.mamoe.net/UserManual.html
|
||||
<delay>3
|
||||
当您遇到问题前,请先查阅
|
||||
<delay>2
|
||||
常见问题参考: https://docs.mirai.mamoe.net/Questions.html
|
||||
<delay>1
|
||||
mirai 历史问题提问: https://github.com/mamoe/mirai/issues?q=is%3Aissue
|
||||
<delay>3
|
||||
|
||||
如果您使用的 mirai-console 来自一个单独整合包,您需要参考该整合包内的 `readme` 文件
|
||||
|
||||
::mirai-console.issuing
|
||||
|
||||
在使用 mirai-console 的过程中,您可能会遇到各种问题。
|
||||
在您向他人咨询前,您需要做好以下准备。
|
||||
<delay>2
|
||||
无论是
|
||||
<delay>2
|
||||
`- 在 mirai 主仓库发起 issue
|
||||
<delay>1
|
||||
`- 在 mirai 论坛发起帖子
|
||||
<delay>1
|
||||
`- 在群聊向他人咨询
|
||||
<delay>1
|
||||
`- 在私聊向他人咨询
|
||||
<delay>1
|
||||
`- 或者更多
|
||||
<delay>1
|
||||
您都需要做好以下准备。
|
||||
<delay>1
|
||||
这不仅能让您更快解决问题,也是对被询问者的尊重。
|
||||
<delay>1
|
||||
|
||||
1. 说明您正在使用的版本
|
||||
<delay>2
|
||||
版本号是确定问题的关键信息,
|
||||
<delay>1
|
||||
mirai-console 的版本号会在 mirai-console 运行时就打印至控制台。
|
||||
其他组件版本可以通过执行 /status 命令获取
|
||||
|
||||
<delay>3
|
||||
2. 携带报错信息 / 携带日志
|
||||
<delay>3
|
||||
报错信息是分析问题的关键,没有日志相当于闭眼开车。
|
||||
<delay>3
|
||||
当您咨询时,一定要携带当时的日志
|
||||
<delay>3
|
||||
「没有日志我能做的事只有帮你算一卦」
|
||||
<delay>3
|
||||
|
||||
标准的咨询模板参考:
|
||||
https://github.com/mamoe/mirai/issues/new?template=bug.yml
|
||||
|
||||
::mirai-core.EncryptService.alert
|
||||
|
||||
Reference: https://github.com/mamoe/mirai/releases/tag/v2.15.0
|
||||
|
||||
关于包数据加密 / 签名 (Internal)(#2716)
|
||||
<delay>2
|
||||
mirai 不会内置任何第三方 签名/加密 服务,而是提供 SPI 让用户自行实现。
|
||||
<delay>2
|
||||
mirai 已经提供了外部 EncryptService SPI 供用户对接。如果您没有能力自行对接,您可以考虑到论坛寻找社区对接。
|
||||
<delay>2
|
||||
在使用社区服务前,您需要了解并理解以下内容
|
||||
<delay>2
|
||||
<pause>
|
||||
|
||||
1. 确认服务来源
|
||||
<delay>2
|
||||
当您安装此服务后,所有的信息都会经过此消息服务。
|
||||
<delay>2
|
||||
这其中包括
|
||||
Bot 的登录请求(包含密码,登录凭证等)
|
||||
<delay>2
|
||||
Bot 发出去的所有信息
|
||||
<delay>2
|
||||
更多.....
|
||||
<delay>2
|
||||
<pause>
|
||||
2. 保护好网络,建立通讯防火墙
|
||||
<delay>2
|
||||
部分服务通讯链路是无加密的
|
||||
<delay>1
|
||||
如果您访问的服务位于公开网络,您的数据有被窃取、拦截的风险。
|
||||
|
||||
<delay>2
|
||||
<pause>
|
||||
3. 保护好日志。
|
||||
<delay>2
|
||||
并非所有日志都能直接传递给他人
|
||||
<pause>
|
||||
|
||||
在您公开您的日志前,请先对日志中的关键信息进行抹除。
|
||||
<pause>
|
||||
|
||||
部分相关服务使用 HTTP GET 请求传递数据体,
|
||||
当远程服务出错时,服务对接可能会直接将此次请求的连接直接输出到日志中,
|
||||
此日志可能包含了此次尝试 签名/加密 的内容,
|
||||
而此内容可能包含关键信息。
|
||||
<pause>
|
||||
|
||||
如果您无法分辨哪些请求需要被抹除时,您可以参考以下规则:
|
||||
<pause>
|
||||
|
||||
请求连接包含大量 Hex 文本,抹除 (Hex: 由 0-9 和 ABCDEF 组成的序列 )
|
||||
<delay>2
|
||||
<pause>
|
||||
请求包含大量 Base64 文本,抹除 (如您不知道什么是 Base64 文本,您可以简单当做是超长的英文与符号组合)
|
||||
<delay>2
|
||||
<pause>
|
||||
请求连接过长,抹除(如连接日志换行了三次都还没有显示完全)
|
||||
<delay>2
|
||||
<pause>
|
||||
|
||||
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.enduserreadme
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* 最终用户须知
|
||||
*
|
||||
* @since 2.16.0
|
||||
*/
|
||||
public class EndUserReadme {
|
||||
public companion object {
|
||||
public const val PAUSE: String = "<pause>"
|
||||
public const val DELAY: String = "<delay>"
|
||||
}
|
||||
|
||||
internal val pages: MutableMap<String, String> = linkedMapOf()
|
||||
|
||||
public class Render {
|
||||
private val msgs = mutableListOf<String>()
|
||||
|
||||
@KeepDetermination
|
||||
public operator fun String.unaryPlus() {
|
||||
msg(this)
|
||||
}
|
||||
|
||||
@KeepDetermination
|
||||
public operator fun plusAssign(s: String) {
|
||||
msg(s)
|
||||
}
|
||||
|
||||
@KeepDetermination
|
||||
public fun pause() {
|
||||
msg(PAUSE)
|
||||
}
|
||||
|
||||
@KeepDetermination
|
||||
public fun delay() {
|
||||
msg(DELAY)
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟一段时间
|
||||
*
|
||||
* @param time 单位:秒
|
||||
*/
|
||||
@KeepDetermination
|
||||
public fun delay(time: Int) {
|
||||
msg(DELAY + time)
|
||||
}
|
||||
|
||||
@KeepDetermination
|
||||
public fun msg(message: String) {
|
||||
msgs.add(message)
|
||||
}
|
||||
|
||||
public fun render(): String = msgs.joinToString(separator = "\n")
|
||||
}
|
||||
|
||||
@KeepDetermination
|
||||
public fun put(category: String, render: Render.() -> Unit) {
|
||||
pages[category] = Render().also(render).render()
|
||||
}
|
||||
|
||||
/**
|
||||
* 同时添加多个须知定义
|
||||
*
|
||||
* 格式:
|
||||
* ```text
|
||||
*
|
||||
* ::category.c1
|
||||
*
|
||||
* Here is c1
|
||||
*
|
||||
* delay 2s
|
||||
* <delay>2
|
||||
*
|
||||
* paused
|
||||
* <pause>
|
||||
*
|
||||
* ::category.c1
|
||||
*
|
||||
* Here is c2
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
@KeepDetermination
|
||||
public fun putAll(fullText: String) {
|
||||
if (fullText.isBlank()) return
|
||||
val lines = LinkedList(fullText.lines())
|
||||
|
||||
var category: String
|
||||
val buffer = mutableListOf<String>()
|
||||
|
||||
while (true) {
|
||||
if (lines.isEmpty()) return
|
||||
val rm = lines.removeFirst()
|
||||
|
||||
if (rm.isBlank()) continue
|
||||
if (rm.startsWith("::")) {
|
||||
category = rm.substring(2)
|
||||
break
|
||||
}
|
||||
throw IllegalArgumentException("First non-empty line must be category define: $rm")
|
||||
}
|
||||
|
||||
fun flush() {
|
||||
while (buffer.isNotEmpty()) {
|
||||
if (buffer.first().isBlank()) {
|
||||
buffer.removeAt(0)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
while (buffer.isNotEmpty()) {
|
||||
if (buffer.last().isBlank()) {
|
||||
buffer.removeAt(buffer.lastIndex)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
pages[category] = buffer.joinToString(separator = "\n")
|
||||
buffer.clear()
|
||||
}
|
||||
|
||||
while (lines.isNotEmpty()) {
|
||||
val rm = lines.removeFirst()
|
||||
if (rm.startsWith("::")) {
|
||||
flush()
|
||||
category = rm.substring(2)
|
||||
continue
|
||||
}
|
||||
buffer.add(rm)
|
||||
}
|
||||
|
||||
flush()
|
||||
}
|
||||
|
||||
@DslMarker
|
||||
private annotation class KeepDetermination
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.events
|
||||
|
||||
import net.mamoe.mirai.console.enduserreadme.EndUserReadme
|
||||
import net.mamoe.mirai.event.AbstractEvent
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
|
||||
public class EndUserReadmeInitializeEvent @MiraiInternalApi constructor(
|
||||
public val readme: EndUserReadme,
|
||||
) : ConsoleEvent, AbstractEvent()
|
@ -46,6 +46,7 @@ import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.Pa
|
||||
import net.mamoe.mirai.console.internal.data.builtins.DataScope
|
||||
import net.mamoe.mirai.console.internal.data.builtins.LoggerConfig
|
||||
import net.mamoe.mirai.console.internal.data.builtins.PluginDependenciesConfig
|
||||
import net.mamoe.mirai.console.internal.enduserreadme.EndUserReadmeProcessor
|
||||
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
|
||||
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorageImpl
|
||||
import net.mamoe.mirai.console.internal.logging.LoggerControllerImpl
|
||||
@ -365,6 +366,10 @@ ___ ____ _ _____ _
|
||||
mainLogger.info { "${pluginManager.plugins.count { it.isEnabled }} plugin(s) enabled." }
|
||||
}
|
||||
|
||||
phase("end-user-readme") {
|
||||
EndUserReadmeProcessor.process(this)
|
||||
}
|
||||
|
||||
phase("auto-login bots") {
|
||||
runBlocking {
|
||||
val config = DataScope.get<AutoLoginConfig>()
|
||||
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.internal.data.builtins
|
||||
|
||||
import net.mamoe.mirai.console.data.PluginDataHolder
|
||||
import net.mamoe.mirai.console.data.PluginDataStorage
|
||||
import net.mamoe.mirai.console.data.ReadOnlyPluginConfig
|
||||
import net.mamoe.mirai.console.data.value
|
||||
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
||||
|
||||
@OptIn(ConsoleExperimentalApi::class)
|
||||
internal class EndUserReadmeData : ReadOnlyPluginConfig("EndUserReadme") {
|
||||
val data: MutableMap<String, String> by value()
|
||||
|
||||
private lateinit var storage_: PluginDataStorage
|
||||
private lateinit var owner_: PluginDataHolder
|
||||
override fun onInit(owner: PluginDataHolder, storage: PluginDataStorage) {
|
||||
this.storage_ = storage
|
||||
this.owner_ = owner
|
||||
}
|
||||
|
||||
internal fun saveNow() {
|
||||
storage_.store(owner_, this)
|
||||
}
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.console.internal.enduserreadme
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import net.mamoe.mirai.console.ConsoleFrontEndImplementation
|
||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||
import net.mamoe.mirai.console.enduserreadme.EndUserReadme
|
||||
import net.mamoe.mirai.console.events.EndUserReadmeInitializeEvent
|
||||
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
|
||||
import net.mamoe.mirai.console.internal.data.builtins.EndUserReadmeData
|
||||
import net.mamoe.mirai.console.util.ConsoleInput
|
||||
import net.mamoe.mirai.console.util.sendAnsiMessage
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
import net.mamoe.mirai.utils.sha256
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
import java.io.File
|
||||
import java.net.InetAddress
|
||||
|
||||
internal object EndUserReadmeProcessor {
|
||||
private val PADDING = "=".repeat(100)
|
||||
private fun StringBuilder.pad(size: Int) {
|
||||
var size0 = size
|
||||
|
||||
while (size0 > 0) {
|
||||
val padded = size0.coerceAtMost(PADDING.length)
|
||||
append(PADDING, 0, padded)
|
||||
size0 -= padded
|
||||
}
|
||||
}
|
||||
|
||||
private fun header(title: String): String {
|
||||
val padding = 100 - title.length
|
||||
|
||||
val lpadding = padding / 2
|
||||
val rpadding = padding - lpadding
|
||||
|
||||
return buildString {
|
||||
pad(lpadding)
|
||||
append(" [ ").append(title).append(" ] ")
|
||||
pad(rpadding)
|
||||
}
|
||||
}
|
||||
|
||||
private val systemDefaultNames = hashSetOf<String>(
|
||||
"ubuntu", "debian", "arch",
|
||||
"centos", "fedora", "localhost",
|
||||
)
|
||||
|
||||
private fun getComputerName(): String {
|
||||
System.getenv("COMPUTERNAME")?.takeUnless(String::isBlank)?.let { return it }
|
||||
System.getenv("HOSTNAME")?.takeUnless(String::isBlank)?.let { return it }
|
||||
|
||||
runCatching {
|
||||
InetAddress.getLocalHost().hostName
|
||||
?.takeIf { it.lowercase() !in systemDefaultNames }
|
||||
?.takeUnless(String::isBlank)
|
||||
?.let { return it }
|
||||
}
|
||||
|
||||
runCatching {
|
||||
File("/etc/machine-id").readText().takeUnless(String::isBlank)?.let { return it.trim() }
|
||||
}
|
||||
return "Unknown Computer"
|
||||
}
|
||||
|
||||
@OptIn(MiraiInternalApi::class, ConsoleFrontEndImplementation::class)
|
||||
fun process(console: MiraiConsoleImplementationBridge) {
|
||||
if (System.getenv("CI") == "true") return
|
||||
if (System.getProperty("mirai.console.skip-end-user-readme") in listOf<String?>("", "true", "yes")) return
|
||||
|
||||
val pcName = getComputerName()
|
||||
val dataObject = EndUserReadmeData()
|
||||
console.consoleDataScope.addAndReloadConfig(dataObject)
|
||||
|
||||
|
||||
runBlocking {
|
||||
val readme = EndUserReadme()
|
||||
runCatching {
|
||||
EndUserReadmeProcessor::class.java.getResourceAsStream("readme.txt")?.bufferedReader()?.use {
|
||||
readme.putAll(it.readText())
|
||||
}
|
||||
}.onFailure { console.mainLogger.error(it) }
|
||||
|
||||
EndUserReadmeInitializeEvent(readme).broadcast()
|
||||
|
||||
// region Remove already read
|
||||
|
||||
val pcNameBCode = pcName.toByteArray()
|
||||
var changed = false
|
||||
|
||||
readme.pages.asSequence().map { (key, value) ->
|
||||
return@map key to value.sha256()
|
||||
}.onEach { (_, hash) ->
|
||||
for (i in hash.indices) {
|
||||
hash[i] = hash[i].toInt().xor(pcNameBCode[i % pcNameBCode.size].toInt()).toByte()
|
||||
}
|
||||
}.map { (k, v) ->
|
||||
return@map k to v.toUHexString()
|
||||
}.toList().forEach { (key, hash) ->
|
||||
if (dataObject.data[key] == hash) {
|
||||
readme.pages.remove(key)
|
||||
} else {
|
||||
dataObject.data[key] = hash
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
suspend fun wait(seconds: Int) {
|
||||
if (seconds < 1) return
|
||||
|
||||
var printWaiting = true
|
||||
|
||||
repeat(seconds) { counter ->
|
||||
val suffix = (seconds - counter).toString() + "s"
|
||||
withTimeoutOrNull(1000L) {
|
||||
if (printWaiting) {
|
||||
ConsoleInput.requestInput("Please wait $suffix...")
|
||||
printWaiting = false
|
||||
}
|
||||
while (true) {
|
||||
ConsoleInput.requestInput("Please read before continuing ($suffix)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suspend fun pause() {
|
||||
ConsoleInput.requestInput("Enter to continue")
|
||||
}
|
||||
|
||||
if (readme.pages.isNotEmpty()) {
|
||||
listOf(
|
||||
header("End User Readme"),
|
||||
"最终用户须知有更新,在您继续使用前,您必须完整阅读新的用户须知。",
|
||||
).forEach { ConsoleCommandSender.sendMessage(it) }
|
||||
}
|
||||
|
||||
readme.pages.forEach { (category, message) ->
|
||||
ConsoleCommandSender.sendMessage(header(category))
|
||||
message.lines().forEach { command ->
|
||||
val ctrim = command.trim()
|
||||
if (ctrim == EndUserReadme.PAUSE) {
|
||||
pause()
|
||||
} else if (ctrim == EndUserReadme.DELAY) {
|
||||
wait(3)
|
||||
} else if (ctrim.startsWith(EndUserReadme.DELAY)) {
|
||||
wait(ctrim.removePrefix(EndUserReadme.DELAY).trim().toIntOrNull() ?: 3)
|
||||
} else {
|
||||
ConsoleCommandSender.sendAnsiMessage(command)
|
||||
}
|
||||
}
|
||||
wait(3)
|
||||
pause()
|
||||
}
|
||||
|
||||
|
||||
if (changed) {
|
||||
dataObject.saveNow()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user