feat(完善banmodule,初步编写dglab模块): 更新版本好,完善BanModule,初步编写dglab模块
This commit is contained in:
parent
88f574eea1
commit
f95c6701e5
124
.idea/uiDesigner.xml
Normal file
124
.idea/uiDesigner.xml
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Palette2">
|
||||||
|
<group name="Swing">
|
||||||
|
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Button" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="RadioButton" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="CheckBox" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Label" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||||
|
<preferred-size width="-1" height="20" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
</group>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||||
|
|
||||||
|
fun k(v: String) = project.property(v) as String
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.9.23"
|
kotlin("jvm") version "1.9.23"
|
||||||
kotlin("plugin.serialization") version "1.9.23" // 添加序列化插件
|
kotlin("plugin.serialization") version "1.9.23" // 添加序列化插件
|
||||||
|
|
@ -7,8 +9,8 @@ plugins {
|
||||||
id("com.github.johnrengelman.shadow") version "8.0.0" // fat jar
|
id("com.github.johnrengelman.shadow") version "8.0.0" // fat jar
|
||||||
}
|
}
|
||||||
|
|
||||||
group = project.property("project_group") as String
|
group = k("project_group")
|
||||||
version = project.property("project_version") as String
|
version = k("project_version")
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
|
||||||
|
|
@ -58,6 +60,16 @@ repositories {
|
||||||
|
|
||||||
// 协程
|
// 协程
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
|
||||||
|
implementation("org.apache.commons:commons-lang3:3.17.0")
|
||||||
|
implementation("com.google.guava:guava:33.3.0-jre")
|
||||||
|
|
||||||
|
//DG_Lab 依赖库导入
|
||||||
|
implementation("io.netty:netty-all:4.1.109.Final")
|
||||||
|
implementation("com.google.code.gson:gson:2.10.1")
|
||||||
|
implementation(files("libs/DgLab-common-${k("dg_lab_version")}.jar"))
|
||||||
|
|
||||||
|
//生成 二维码
|
||||||
|
implementation("com.google.zxing:core:[3.5.3,)")
|
||||||
|
|
||||||
// 测试
|
// 测试
|
||||||
testImplementation(kotlin("test"))
|
testImplementation(kotlin("test"))
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,5 @@ org.gradle.downloadSources=false
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.degree_of_parallelism=16
|
org.gradle.degree_of_parallelism=16
|
||||||
project_group=top.r3944realms.ltdmanager
|
project_group=top.r3944realms.ltdmanager
|
||||||
project_version=1.6-SNAPSHOT
|
project_version=1.10-SNAPSHOT
|
||||||
|
dg_lab_version=4.2.11.18
|
||||||
|
|
|
||||||
BIN
libs/DgLab-common-4.2.11.18.jar
Normal file
BIN
libs/DgLab-common-4.2.11.18.jar
Normal file
Binary file not shown.
|
|
@ -0,0 +1,130 @@
|
||||||
|
package top.r3944realms.ltdmanager.core.config
|
||||||
|
|
||||||
|
import top.r3944realms.ltdmanager.utils.CryptoUtil
|
||||||
|
import top.r3944realms.ltdmanager.utils.YamlUpdater
|
||||||
|
|
||||||
|
|
||||||
|
data class DgLabConfig(
|
||||||
|
var wsServer: WsServerConfig = WsServerConfig(),
|
||||||
|
var dgLabClient: DgLabClientConfig = DgLabClientConfig(),
|
||||||
|
var pulseData: PulseDataConfig = PulseDataConfig(),
|
||||||
|
var commandText: CommandTextConfig = CommandTextConfig(),
|
||||||
|
var replyText: ReplyTextConfig = ReplyTextConfig(),
|
||||||
|
var debug: DebugConfig = DebugConfig()
|
||||||
|
) {
|
||||||
|
data class WsServerConfig(
|
||||||
|
var localServerUrl: String = "0.0.0.0",
|
||||||
|
var localServerPort: Int = 4567,
|
||||||
|
var localServerPublishUrl: String = "ws://127.0.0.1:4567",
|
||||||
|
var localServerSecure: Boolean = false,
|
||||||
|
var localServerSslCert: String = "",
|
||||||
|
var localServerSslKey: String = "",
|
||||||
|
var encryptedLocalServerSslPassword: String? = null
|
||||||
|
) {
|
||||||
|
val decryptedLocalServerSslPassword: String?
|
||||||
|
get() {
|
||||||
|
if (encryptedLocalServerSslPassword == null) return null
|
||||||
|
if (!isEncrypted()) return encryptedLocalServerSslPassword
|
||||||
|
return try {
|
||||||
|
val cipherText = encryptedLocalServerSslPassword!!.substring(4, encryptedLocalServerSslPassword!!.length - 1)
|
||||||
|
CryptoUtil.decrypt(cipherText)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IllegalStateException("localServerSslPassword 解密失败", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun encryptPassword() {
|
||||||
|
if (encryptedLocalServerSslPassword == null || isEncrypted()) return
|
||||||
|
try {
|
||||||
|
encryptedLocalServerSslPassword = "ENC(${CryptoUtil.encrypt(encryptedLocalServerSslPassword!!)})"
|
||||||
|
YamlUpdater.updateYaml(
|
||||||
|
YamlConfigLoader.configFilePath.toString(),
|
||||||
|
"dg-lab.ws-server.encrypted-local-server-ssl-password",
|
||||||
|
encryptedLocalServerSslPassword!!
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw IllegalStateException("SSL 密码加密失败", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isEncrypted(): Boolean {
|
||||||
|
return encryptedLocalServerSslPassword != null &&
|
||||||
|
encryptedLocalServerSslPassword!!.startsWith("ENC(") &&
|
||||||
|
encryptedLocalServerSslPassword!!.endsWith(")")
|
||||||
|
}
|
||||||
|
//TODO: 添加有效性检测
|
||||||
|
fun validate() {
|
||||||
|
require(localServerUrl.isNotBlank()) { "localServerUrl 未配置" }
|
||||||
|
require(localServerPort > 0) { "localServerPort 必须大于 0" }
|
||||||
|
require(localServerPublishUrl.isNotBlank()) { "localServerPublishUrl 未配置" }
|
||||||
|
if (localServerSecure) {
|
||||||
|
require(localServerSslCert.isNotBlank()) { "启用 SSL 时必须配置 localServerSslCert" }
|
||||||
|
require(localServerSslKey.isNotBlank()) { "启用 SSL 时必须配置 localServerSslKey" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class DgLabClientConfig(
|
||||||
|
var bindTimeout: Double = 90.0,
|
||||||
|
var registerTimeout: Double = 30.0
|
||||||
|
)
|
||||||
|
|
||||||
|
data class PulseDataConfig(
|
||||||
|
var customPulseData: String = "data/dg-lab-play/customPulseData.json",
|
||||||
|
var durationPerPost: Double = 8.0,
|
||||||
|
var postInterval: Double = 1.0,
|
||||||
|
var sleepAfterClear: Double = 0.5
|
||||||
|
) {
|
||||||
|
fun validate(maxLength: Double) {
|
||||||
|
require(durationPerPost <= maxLength * 0.1) { "PulseDataConfig.durationPerPost 超出最大时长" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class CommandTextConfig(
|
||||||
|
var appendPulse: String = "增加波形",
|
||||||
|
var currentPulse: String = "当前波形",
|
||||||
|
var currentStrength: String = "当前强度",
|
||||||
|
var decreaseStrength: String = "减小强度",
|
||||||
|
var dgLabDeviceJoin: String = "绑定郊狼",
|
||||||
|
var exitGame: String = "退出游戏",
|
||||||
|
var increaseStrength: String = "加大强度",
|
||||||
|
var randomPulse: String = "随机波形",
|
||||||
|
var randomStrength: String = "随机强度",
|
||||||
|
var resetPulse: String = "重置波形",
|
||||||
|
var showPlayers: String = "当前玩家",
|
||||||
|
var showPulses: String = "可用波形",
|
||||||
|
var usage: String = "郊狼玩法"
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ReplyTextConfig(
|
||||||
|
var bindTimeout: String = "绑定超时",
|
||||||
|
var currentPlayers: String = "当前玩家:",
|
||||||
|
var currentPulse: String = "当前波形循环为:【{}】",
|
||||||
|
var currentStrength: String = "A通道:{0}/{1} B通道:{2}/{3}",
|
||||||
|
var failedToCreateClient: String = "创建 DG-Lab 控制终端失败",
|
||||||
|
var failedToFetchStrengthInfo: String = "获取通道强度状态失败",
|
||||||
|
var failedToFetchStrengthLimit: String = "获取通道强度上限失败,控制失败",
|
||||||
|
var gameExited: String = "已退出游戏",
|
||||||
|
var invalidPulseParam: String = "波形参数错误,控制失败",
|
||||||
|
var invalidStrengthParam: String = "强度参数错误,控制失败",
|
||||||
|
var invalidTarget: String = "目标玩家不存在或郊狼 App 未绑定",
|
||||||
|
var noAvailablePulse: String = "无可用波形",
|
||||||
|
var noPlayer: String = "当前没有已连接的玩家,你可以绑定试试~",
|
||||||
|
var notBindYet: String = "你目前没有绑定 DG-Lab App",
|
||||||
|
var pleaseAtTarget: String = "使用命令的同时请 @ 想要控制的玩家",
|
||||||
|
var pleaseScanQrcode: String = "请用 DG-Lab App 扫描二维码以连接",
|
||||||
|
var pleaseSetPulseFirst: String = "请先设置郊狼波形:{}",
|
||||||
|
var pulsesEmpty: String = "当前波形循环为空",
|
||||||
|
var successfullyBind: String = "绑定成功,可以开始色色了!",
|
||||||
|
var successfullyDecreased: String = "郊狼强度减小了 {}%",
|
||||||
|
var successfullyIncreased: String = "郊狼强度加强了 {}%!",
|
||||||
|
var successfullySetPulse: String = "郊狼波形成功设置为【{}】!",
|
||||||
|
var successfullySetToStrength: String = "郊狼强度成功设置为 {}%!"
|
||||||
|
)
|
||||||
|
|
||||||
|
data class DebugConfig(
|
||||||
|
var enableDebug: Boolean = false,
|
||||||
|
var ideHost: String = "127.0.0.1",
|
||||||
|
var idePort: Int = 5678
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -34,6 +34,7 @@ object YamlConfigLoader {
|
||||||
config?.mail?.encryptPassword()
|
config?.mail?.encryptPassword()
|
||||||
config?.tools?.rcon?.encryptPassword()
|
config?.tools?.rcon?.encryptPassword()
|
||||||
config?.blessingSkinServer?.invitationApi?.encryptToken()
|
config?.blessingSkinServer?.invitationApi?.encryptToken()
|
||||||
|
config?.dgLab?.wsServer?.encryptPassword()
|
||||||
}
|
}
|
||||||
private fun loadConfig(): ConfigWrapper {
|
private fun loadConfig(): ConfigWrapper {
|
||||||
if (!Files.exists(configFilePath)) {
|
if (!Files.exists(configFilePath)) {
|
||||||
|
|
@ -76,6 +77,7 @@ object YamlConfigLoader {
|
||||||
fun loadToolConfig(): ToolConfig = config.tools
|
fun loadToolConfig(): ToolConfig = config.tools
|
||||||
fun loadMailConfig(): MailConfig = config.mail
|
fun loadMailConfig(): MailConfig = config.mail
|
||||||
fun loadBlessingSkinServerConfig(): BlessingSkinServerConfig = config.blessingSkinServer
|
fun loadBlessingSkinServerConfig(): BlessingSkinServerConfig = config.blessingSkinServer
|
||||||
|
fun loadDgLabConfig(): DgLabConfig = config.dgLab
|
||||||
data class ConfigWrapper(
|
data class ConfigWrapper(
|
||||||
var database: DatabaseConfig = DatabaseConfig(),
|
var database: DatabaseConfig = DatabaseConfig(),
|
||||||
var crypto: CryptoConfig = CryptoConfig(),
|
var crypto: CryptoConfig = CryptoConfig(),
|
||||||
|
|
@ -85,6 +87,7 @@ object YamlConfigLoader {
|
||||||
var tools: ToolConfig = ToolConfig(),
|
var tools: ToolConfig = ToolConfig(),
|
||||||
var mail: MailConfig = MailConfig(),
|
var mail: MailConfig = MailConfig(),
|
||||||
var blessingSkinServer: BlessingSkinServerConfig = BlessingSkinServerConfig(),
|
var blessingSkinServer: BlessingSkinServerConfig = BlessingSkinServerConfig(),
|
||||||
|
var dgLab: DgLabConfig = DgLabConfig(),
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.manager
|
||||||
|
|
||||||
|
import com.r3944realms.dg_lab.manager.DGPBClientManager
|
||||||
|
|
||||||
|
class ClientManager(
|
||||||
|
private val clients: MutableMap<String, DGPBClientManager> = mutableMapOf(),
|
||||||
|
) : IManager<MutableMap<String, DGPBClientManager>> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加单例客户端管理示例
|
||||||
|
* @param key 唯一标识客户端管理的 key,比如 ID 或 name
|
||||||
|
*/
|
||||||
|
fun addClient(key: String, client: DGPBClientManager) {
|
||||||
|
clients[key] = client
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除单例客户端管理实例
|
||||||
|
*/
|
||||||
|
fun removeClient(key: String) {
|
||||||
|
clients.remove(key)?.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 key 获取客户端
|
||||||
|
*/
|
||||||
|
fun getClient(key: String): DGPBClientManager? {
|
||||||
|
return clients[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动所有客户端
|
||||||
|
*/
|
||||||
|
override fun startAll() {
|
||||||
|
clients.values.forEach { it.start() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止所有客户端
|
||||||
|
*/
|
||||||
|
override fun stopAll() {
|
||||||
|
clients.values.forEach { it.stop() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取内部 Map 实例
|
||||||
|
*/
|
||||||
|
override fun getInstance(): MutableMap<String, DGPBClientManager> {
|
||||||
|
return clients
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.manager
|
||||||
|
|
||||||
|
import com.r3944realms.dg_lab.api.operation.ClientOperation
|
||||||
|
import com.r3944realms.dg_lab.api.operation.ServerOperation
|
||||||
|
import com.r3944realms.dg_lab.api.websocket.message.role.WebSocketClientRole
|
||||||
|
import com.r3944realms.dg_lab.api.websocket.message.role.WebSocketServerRole
|
||||||
|
import com.r3944realms.dg_lab.manager.DGPBClientManager
|
||||||
|
import com.r3944realms.dg_lab.manager.DGPBServerManager
|
||||||
|
import com.r3944realms.dg_lab.websocket.PowerBoxWSClient
|
||||||
|
import com.r3944realms.dg_lab.websocket.PowerBoxWSServer
|
||||||
|
import com.r3944realms.dg_lab.websocket.sharedData.ClientPowerBoxSharedData
|
||||||
|
import com.r3944realms.dg_lab.websocket.sharedData.ServerPowerBoxSharedData
|
||||||
|
import top.r3944realms.ltdmanager.core.config.YamlConfigLoader
|
||||||
|
import kotlin.io.path.Path
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局DG_Lab单例管理器
|
||||||
|
*/
|
||||||
|
object DgLabManager {
|
||||||
|
// 可空,延迟初始化
|
||||||
|
var serverManager: ServerManager? = null
|
||||||
|
private set
|
||||||
|
|
||||||
|
var clientManager: ClientManager? = null
|
||||||
|
private set
|
||||||
|
|
||||||
|
|
||||||
|
fun createServerManager(operation: ServerOperation): DGPBServerManager {
|
||||||
|
val loadDgLabConfig = YamlConfigLoader.loadDgLabConfig()
|
||||||
|
val boxWSServer = PowerBoxWSServer.Builder.getBuilder()
|
||||||
|
.port(loadDgLabConfig.wsServer.localServerPort)
|
||||||
|
.role(WebSocketServerRole("Se-IC"))
|
||||||
|
.operation(operation)
|
||||||
|
.sharedData(ServerPowerBoxSharedData())
|
||||||
|
.build()
|
||||||
|
if (loadDgLabConfig.wsServer.localServerSecure) {
|
||||||
|
boxWSServer.enableSSL(Path(loadDgLabConfig.wsServer.localServerSslCert).toFile(), Path(loadDgLabConfig.wsServer.localServerSslKey).toFile(), loadDgLabConfig.wsServer.decryptedLocalServerSslPassword)
|
||||||
|
}
|
||||||
|
val dgpbServerManager = DGPBServerManager(boxWSServer)
|
||||||
|
return dgpbServerManager
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 服务器管理类
|
||||||
|
*/
|
||||||
|
fun initServerManager(server: DGPBServerManager) {
|
||||||
|
serverManager = ServerManager(server)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 初始化 客户端管理类
|
||||||
|
*/
|
||||||
|
fun initClientManager() {
|
||||||
|
clientManager = ClientManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加 客户端管理类
|
||||||
|
*/
|
||||||
|
fun addClient(key: String, client: DGPBClientManager) {
|
||||||
|
clientManager?.addClient(key, client)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除 客户端管理类
|
||||||
|
*/
|
||||||
|
fun removeClient(key: String) {
|
||||||
|
clientManager?.removeClient(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 客户端管理类
|
||||||
|
*/
|
||||||
|
fun getClient(key: String): DGPBClientManager? {
|
||||||
|
return clientManager?.getClient(key)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取 & 创建 客户端管理类
|
||||||
|
*/
|
||||||
|
fun getClientOrCreate(key: String, operation: ClientOperation): DGPBClientManager {
|
||||||
|
val client = getClient(key)
|
||||||
|
if (client == null) {
|
||||||
|
val loadDgLabConfig = YamlConfigLoader.loadDgLabConfig()
|
||||||
|
val boxWSClient = PowerBoxWSClient.Builder.getBuilder()
|
||||||
|
.address(loadDgLabConfig.wsServer.localServerUrl)
|
||||||
|
.port(loadDgLabConfig.wsServer.localServerPort)
|
||||||
|
.role(WebSocketClientRole("QQ-$key"))
|
||||||
|
.operation(operation)
|
||||||
|
.sharedData(ClientPowerBoxSharedData())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
if (loadDgLabConfig.wsServer.localServerSecure) {
|
||||||
|
boxWSClient.enableSSL()
|
||||||
|
}
|
||||||
|
val clientManager = DGPBClientManager(
|
||||||
|
boxWSClient
|
||||||
|
)
|
||||||
|
this.clientManager?.addClient(key, clientManager)
|
||||||
|
return clientManager
|
||||||
|
}
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.manager
|
||||||
|
|
||||||
|
interface IManager<T> {
|
||||||
|
fun startAll()
|
||||||
|
fun stopAll()
|
||||||
|
fun getInstance(): T?
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.manager
|
||||||
|
|
||||||
|
import com.r3944realms.dg_lab.api.manager.IDGLabManager
|
||||||
|
import com.r3944realms.dg_lab.api.manager.Status
|
||||||
|
import com.r3944realms.dg_lab.api.websocket.sharedData.ISharedData
|
||||||
|
import com.r3944realms.dg_lab.manager.DGPBServerManager
|
||||||
|
|
||||||
|
class ServerManager(
|
||||||
|
private val server: DGPBServerManager
|
||||||
|
) : IManager<DGPBServerManager>, IDGLabManager {
|
||||||
|
|
||||||
|
override fun startAll() {
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stopAll() {
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun start() {
|
||||||
|
server.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stop() {
|
||||||
|
server.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSharedData(): ISharedData {
|
||||||
|
return server.sharedData
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStatus(): Status {
|
||||||
|
return server.status
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setStatus(p0: Status?) {
|
||||||
|
server.status = p0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getInstance(): DGPBServerManager {
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.game
|
||||||
|
|
||||||
|
import com.r3944realms.dg_lab.api.operation.ClientOperation
|
||||||
|
import com.r3944realms.dg_lab.api.websocket.message.data.PowerBoxData
|
||||||
|
|
||||||
|
class GameClientOperation(
|
||||||
|
val player: Player
|
||||||
|
) : ClientOperation {
|
||||||
|
|
||||||
|
override fun ClientStartingHandler() {
|
||||||
|
println("Player ${player.id} is starting the client...")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ClientStartedHandler() {
|
||||||
|
println("Player ${player.id} client started successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ClientStartingErrorHandler() {
|
||||||
|
println("Player ${player.id} failed to start client!")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ClientStoppingHandler() {
|
||||||
|
println("Player ${player.id} is stopping the client...")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ClientStoppingErrorHandler() {
|
||||||
|
println("Player ${player.id} encountered an error while stopping.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ClientStoppedHandler() {
|
||||||
|
println("Player ${player.id} client stopped.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun QrCodeUrlHandler(p0: String?) {
|
||||||
|
println("Player ${player.id} QR code received: $p0")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ShowQrCodeHandler() {
|
||||||
|
println("Player ${player.id} should display QR code.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ConnectSuccessfulNoticeHandler() {
|
||||||
|
println("Player ${player.id} connected successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun DisconnectHandler(p0: PowerBoxData?) {
|
||||||
|
println("Player ${player.id} disconnected: $p0")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun ErrorHandler(p0: PowerBoxData?) {
|
||||||
|
println("Player ${player.id} error occurred: $p0")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun HeartBeatHandler(p0: PowerBoxData?) {
|
||||||
|
println("Heartbeat from player ${player.id}: $p0")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun OtherMessageHandler(p0: PowerBoxData?) {
|
||||||
|
println("Other message for player ${player.id}: $p0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.game
|
||||||
|
|
||||||
|
import com.r3944realms.dg_lab.websocket.handler.server.DefaultServerOperation
|
||||||
|
|
||||||
|
class GameServerOperation : DefaultServerOperation()
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.game
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 玩家类,目前仅包含一个 ID
|
||||||
|
*/
|
||||||
|
data class Player(
|
||||||
|
val id: String
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.pulseware
|
||||||
|
|
||||||
|
import com.r3944realms.dg_lab.api.message.data.PulseWave
|
||||||
|
import com.r3944realms.dg_lab.api.message.data.PulseWaveList
|
||||||
|
|
||||||
|
|
||||||
|
object CustomPulseDataConverter {
|
||||||
|
/**
|
||||||
|
* 将自定义波形数据转换为 PulseWaveList
|
||||||
|
*
|
||||||
|
* @param customPulseData Map<String></String>, List<int></int>[][]>>
|
||||||
|
* 每个 int[][] 包含两个长度为 4 的 int 数组,第一个是 frequencies,第二个是 strengths
|
||||||
|
* @return Map<String></String>, PulseWaveList>
|
||||||
|
*/
|
||||||
|
fun convert(customPulseData: Map<String, List<Array<IntArray>>>): Map<String, PulseWaveList> {
|
||||||
|
val pulseWaveLists: MutableMap<String, PulseWaveList> = HashMap()
|
||||||
|
|
||||||
|
for ((name, operations) in customPulseData) {
|
||||||
|
val waveList = PulseWaveList()
|
||||||
|
waveList.name = name
|
||||||
|
|
||||||
|
for (op in operations) {
|
||||||
|
val freqs = op[0]
|
||||||
|
val strengths = op[1]
|
||||||
|
|
||||||
|
// 确保每个数组长度为4
|
||||||
|
require(!(freqs.size != 4 || strengths.size != 4)) { "每个波形段必须包含 4 个频率和 4 个强度值" }
|
||||||
|
|
||||||
|
val wave = PulseWave.fromArrays(freqs, strengths)
|
||||||
|
waveList.add(wave)
|
||||||
|
}
|
||||||
|
|
||||||
|
pulseWaveLists[name] = waveList
|
||||||
|
}
|
||||||
|
|
||||||
|
return pulseWaveLists
|
||||||
|
}
|
||||||
|
fun PulseWave.toSerializable(): PulseWaveSerializable =
|
||||||
|
PulseWaveSerializable(f1(), f2(), f3(), f4(), s1(), s2(), s3(), s4())
|
||||||
|
|
||||||
|
fun PulseWaveSerializable.toPulseWave(): PulseWave =
|
||||||
|
PulseWave.fromArrays(
|
||||||
|
intArrayOf(f1, f2, f3, f4),
|
||||||
|
intArrayOf(s1, s2, s3, s4)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun PulseWaveList.toSerializable(): PulseWaveListSerializable =
|
||||||
|
PulseWaveListSerializable(name, list.map { it.toSerializable() }.toMutableList())
|
||||||
|
|
||||||
|
fun PulseWaveListSerializable.toPulseWaveList(): PulseWaveList {
|
||||||
|
val listObj = PulseWaveList()
|
||||||
|
listObj.setName(name)
|
||||||
|
list.forEach { listObj.add(it.toPulseWave()) }
|
||||||
|
return listObj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,313 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.pulseware
|
||||||
|
|
||||||
|
import com.r3944realms.dg_lab.api.message.data.PulseWave
|
||||||
|
import com.r3944realms.dg_lab.api.message.data.PulseWaveList
|
||||||
|
|
||||||
|
object DefaultPulseData {
|
||||||
|
|
||||||
|
fun allPulseWaveLists(): Map<String, PulseWaveList> {
|
||||||
|
return mapOf(
|
||||||
|
"呼吸" to Breath,
|
||||||
|
"潮汐" to Tide,
|
||||||
|
"连击" to Combo,
|
||||||
|
"快速按捏" to FastPinch,
|
||||||
|
"按捏渐强" to PinchGradual,
|
||||||
|
"心跳节奏" to Heartbeat,
|
||||||
|
"压缩" to Compress,
|
||||||
|
"节奏步伐" to RhythmStep,
|
||||||
|
"颗粒摩擦" to GranularFriction,
|
||||||
|
"渐变弹跳" to GradualBounce,
|
||||||
|
"波浪涟漪" to WaveRipple,
|
||||||
|
"雨水冲刷" to RainWash,
|
||||||
|
"变速敲击" to SpeedHit,
|
||||||
|
"信号灯" to SignalLight,
|
||||||
|
"挑逗1" to Tease1,
|
||||||
|
"挑逗2" to Tease2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val Breath: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "呼吸"
|
||||||
|
|
||||||
|
// 每段频率和强度
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 5, 10, 20)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(20, 25, 30, 40)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(40, 45, 50, 60)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(60, 65, 70, 80)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(0, 0, 0, 0), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(0, 0, 0, 0), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(0, 0, 0, 0), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
|
||||||
|
// 转成 PulseWave 并加入列表
|
||||||
|
for (seg in segments) {
|
||||||
|
list.add(PulseWave.fromArrays(seg[0], seg[1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
list
|
||||||
|
}
|
||||||
|
val Tide: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "潮汐"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 4, 8, 17)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(17, 21, 25, 33)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(50, 50, 50, 50)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(50, 54, 58, 67)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(67, 71, 75, 83)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 98, 96, 92)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(92, 90, 88, 84)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(84, 82, 80, 76)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(68, 68, 68, 68))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
val Combo: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "连击"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 92, 84, 67)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(67, 58, 50, 33)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 1)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(2, 2, 2, 2))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
val FastPinch: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "快速按捏"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(0, 0, 0, 0), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
val PinchGradual: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "按捏渐强"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(29, 29, 29, 29)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(52, 52, 52, 52)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(2, 2, 2, 2)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(73, 73, 73, 73)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(87, 87, 87, 87)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
val Heartbeat: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "心跳节奏"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(110, 110, 110, 110), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(110, 110, 110, 110), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(75, 75, 75, 75)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(75, 77, 79, 83)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(83, 85, 88, 92)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
val Compress: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "压缩"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(25, 25, 24, 24), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(24, 23, 23, 23), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(22, 22, 22, 21), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(21, 21, 20, 20), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(20, 19, 19, 19), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(18, 18, 18, 17), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(17, 16, 16, 16), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(15, 15, 15, 14), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(14, 14, 13, 13), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(13, 12, 12, 12), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(11, 11, 11, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
val RhythmStep: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "节奏步伐"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 5, 10, 20)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(20, 25, 30, 40)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(40, 45, 50, 60)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(60, 65, 70, 80)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 6, 12, 25)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(25, 31, 38, 50)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(50, 56, 62, 75)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 8, 16, 33)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(33, 42, 50, 67)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 12, 25, 50)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
val GranularFriction: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "颗粒摩擦"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
val GradualBounce: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "渐变弹跳"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(1, 1, 1, 1)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(1, 9, 18, 34)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(34, 42, 50, 67)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(0, 0, 0, 0), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(0, 0, 0, 0), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
val WaveRipple: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "波浪涟漪"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(1, 1, 1, 1)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(1, 3, 7, 13)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(13, 25, 40, 60)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(60, 75, 90, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(50, 50, 50, 50)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
val RainWash: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "雨水冲刷"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 5, 15, 30)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(40, 50, 60, 70)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(80, 90, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
val SpeedHit: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "变速敲击"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(15, 15, 15, 15), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(20, 20, 20, 20), intArrayOf(50, 50, 50, 50)),
|
||||||
|
arrayOf(intArrayOf(25, 25, 25, 25), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(20, 20, 20, 20), intArrayOf(50, 50, 50, 50)),
|
||||||
|
arrayOf(intArrayOf(15, 15, 15, 15), intArrayOf(0, 0, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
val SignalLight: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "信号灯"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 0, 0, 0)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 100, 100, 100))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
val Tease1: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "挑逗1"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 30, 60, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 70, 40, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
|
||||||
|
val Tease2: PulseWaveList by lazy {
|
||||||
|
val list = PulseWaveList()
|
||||||
|
list.name = "挑逗2"
|
||||||
|
val segments = listOf(
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(0, 50, 100, 100)),
|
||||||
|
arrayOf(intArrayOf(10, 10, 10, 10), intArrayOf(100, 50, 0, 0))
|
||||||
|
)
|
||||||
|
segments.forEach { list.add(PulseWave.fromArrays(it[0], it[1])) }
|
||||||
|
list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.pulseware
|
||||||
|
|
||||||
|
class PulseWaveClassTransform {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.pulseware
|
||||||
|
|
||||||
|
import com.r3944realms.dg_lab.api.message.data.PulseWaveList
|
||||||
|
import kotlinx.serialization.builtins.MapSerializer
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import top.r3944realms.ltdmanager.dglab.model.pulseware.CustomPulseDataConverter.toPulseWaveList
|
||||||
|
import top.r3944realms.ltdmanager.dglab.model.pulseware.CustomPulseDataConverter.toSerializable
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object PulseWaveJsonIO {
|
||||||
|
private val json = Json {
|
||||||
|
prettyPrint = true
|
||||||
|
encodeDefaults = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveToFile(map: Map<String, PulseWaveList>, file: File) {
|
||||||
|
val serializableMap = map.mapValues { it.value.toSerializable() }
|
||||||
|
file.writeText(json.encodeToString(serializableMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadFromFile(file: File): Map<String, PulseWaveList> {
|
||||||
|
if (!file.exists()) return emptyMap()
|
||||||
|
val type = MapSerializer(String.serializer(), PulseWaveListSerializable.serializer())
|
||||||
|
val data: Map<String, PulseWaveListSerializable> = json.decodeFromString(type, file.readText())
|
||||||
|
return data.mapValues { it.value.toPulseWaveList() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.pulseware
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PulseWaveListSerializable(
|
||||||
|
var name: String = "",
|
||||||
|
val list: MutableList<PulseWaveSerializable> = mutableListOf()
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package top.r3944realms.ltdmanager.dglab.model.pulseware
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class PulseWaveSerializable(
|
||||||
|
val f1: Int, val f2: Int, val f3: Int, val f4: Int,
|
||||||
|
val s1: Int, val s2: Int, val s3: Int, val s4: Int
|
||||||
|
)
|
||||||
|
|
@ -23,6 +23,7 @@ fun main() = GlobalManager.runBlockingMain {
|
||||||
)
|
)
|
||||||
val helpModule = HelpModule(
|
val helpModule = HelpModule(
|
||||||
moduleName = "WhiteListGroup",
|
moduleName = "WhiteListGroup",
|
||||||
|
keywords = listOf("help", "帮助"),
|
||||||
groupMessagePollingModule = groupMsgPollingModule,
|
groupMessagePollingModule = groupMsgPollingModule,
|
||||||
selfId = selfQQId,
|
selfId = selfQQId,
|
||||||
selfNickName = selfNickName,
|
selfNickName = selfNickName,
|
||||||
|
|
@ -83,16 +84,18 @@ fun main() = GlobalManager.runBlockingMain {
|
||||||
moduleName = "WhiteListGroup",
|
moduleName = "WhiteListGroup",
|
||||||
groupMessagePollingModule = groupMsgPollingModule,
|
groupMessagePollingModule = groupMsgPollingModule,
|
||||||
selfId = selfQQId,
|
selfId = selfQQId,
|
||||||
commandPrefixList = listOf("口球", "mute", "杂鱼三九"),
|
adminsId = listOf(1283411677),
|
||||||
|
muteCommandPrefixList = listOf("口球", "mute", "Mute", "禁言"),
|
||||||
|
unmuteCommandPrefixList = listOf("解禁", "unmute", "Unmute", "解除禁言"),
|
||||||
minBanMinutes = 1,
|
minBanMinutes = 1,
|
||||||
maxBanMinutes = 15,
|
maxBanMinutes = 15,
|
||||||
)
|
)
|
||||||
val modGroupHandlerModule = ModGroupHandlerModule(
|
// val modGroupHandlerModule = ModGroupHandlerModule(
|
||||||
moduleName = "ModGroup",
|
// moduleName = "ModGroup",
|
||||||
targetGroupId = 339340846,
|
// targetGroupId = 339340846,
|
||||||
answers = listOf("戏鸢", "一只戏鸢", "折戏鸢", "LostInLinearPast", "lostinlinearpast"),
|
// answers = listOf("戏鸢", "一只戏鸢", "折戏鸢", "LostInLinearPast", "lostinlinearpast"),
|
||||||
pollIntervalMillis = 15_000L,
|
// pollIntervalMillis = 15_000L,
|
||||||
)
|
// )
|
||||||
|
|
||||||
// 注册模块到全局模块管理器
|
// 注册模块到全局模块管理器
|
||||||
GlobalManager.moduleManager.registerModule(groupModule)
|
GlobalManager.moduleManager.registerModule(groupModule)
|
||||||
|
|
@ -103,7 +106,7 @@ fun main() = GlobalManager.runBlockingMain {
|
||||||
GlobalManager.moduleManager.registerModule(invitationCodesModule)
|
GlobalManager.moduleManager.registerModule(invitationCodesModule)
|
||||||
GlobalManager.moduleManager.registerModule(helpModule)
|
GlobalManager.moduleManager.registerModule(helpModule)
|
||||||
GlobalManager.moduleManager.registerModule(banModule)
|
GlobalManager.moduleManager.registerModule(banModule)
|
||||||
GlobalManager.moduleManager.registerModule(modGroupHandlerModule)
|
// GlobalManager.moduleManager.registerModule(modGroupHandlerModule)
|
||||||
|
|
||||||
// 加载模块
|
// 加载模块
|
||||||
GlobalManager.moduleManager.loadModule(groupModule.name)
|
GlobalManager.moduleManager.loadModule(groupModule.name)
|
||||||
|
|
@ -114,5 +117,5 @@ fun main() = GlobalManager.runBlockingMain {
|
||||||
GlobalManager.moduleManager.loadModule(invitationCodesModule.name)
|
GlobalManager.moduleManager.loadModule(invitationCodesModule.name)
|
||||||
GlobalManager.moduleManager.loadModule(helpModule.name)
|
GlobalManager.moduleManager.loadModule(helpModule.name)
|
||||||
GlobalManager.moduleManager.loadModule(banModule.name)
|
GlobalManager.moduleManager.loadModule(banModule.name)
|
||||||
GlobalManager.moduleManager.loadModule(modGroupHandlerModule.name)
|
// GlobalManager.moduleManager.loadModule(modGroupHandlerModule.name)
|
||||||
}
|
}
|
||||||
|
|
@ -6,12 +6,15 @@ import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import top.r3944realms.ltdmanager.module.common.CommandParser
|
import top.r3944realms.ltdmanager.module.common.CommandParser
|
||||||
import top.r3944realms.ltdmanager.module.common.filter.TriggerMessageFilter
|
import top.r3944realms.ltdmanager.module.common.filter.TriggerMessageFilter
|
||||||
import top.r3944realms.ltdmanager.module.common.filter.type.CommandFilter
|
|
||||||
import top.r3944realms.ltdmanager.module.common.filter.type.IgnoreSelfFilter
|
import top.r3944realms.ltdmanager.module.common.filter.type.IgnoreSelfFilter
|
||||||
|
import top.r3944realms.ltdmanager.module.common.filter.type.MultiCommandFilter
|
||||||
import top.r3944realms.ltdmanager.module.common.filter.type.NewMessageFilter
|
import top.r3944realms.ltdmanager.module.common.filter.type.NewMessageFilter
|
||||||
import top.r3944realms.ltdmanager.napcat.data.ID
|
import top.r3944realms.ltdmanager.napcat.data.ID
|
||||||
import top.r3944realms.ltdmanager.napcat.data.MessageElement
|
import top.r3944realms.ltdmanager.napcat.data.MessageElement
|
||||||
|
import top.r3944realms.ltdmanager.napcat.data.MessageType
|
||||||
|
import top.r3944realms.ltdmanager.napcat.event.group.GetGroupShutListEvent
|
||||||
import top.r3944realms.ltdmanager.napcat.event.message.GetFriendMsgHistoryEvent
|
import top.r3944realms.ltdmanager.napcat.event.message.GetFriendMsgHistoryEvent
|
||||||
|
import top.r3944realms.ltdmanager.napcat.request.group.GetGroupShutListRequest
|
||||||
import top.r3944realms.ltdmanager.napcat.request.group.SetGroupBanRequest
|
import top.r3944realms.ltdmanager.napcat.request.group.SetGroupBanRequest
|
||||||
import top.r3944realms.ltdmanager.napcat.request.other.SendGroupMsgRequest
|
import top.r3944realms.ltdmanager.napcat.request.other.SendGroupMsgRequest
|
||||||
import top.r3944realms.ltdmanager.utils.LoggerUtil
|
import top.r3944realms.ltdmanager.utils.LoggerUtil
|
||||||
|
|
@ -25,13 +28,18 @@ class BanModule(
|
||||||
moduleName: String,
|
moduleName: String,
|
||||||
private val groupMessagePollingModule : GroupMessagePollingModule,
|
private val groupMessagePollingModule : GroupMessagePollingModule,
|
||||||
private val selfId: Long,
|
private val selfId: Long,
|
||||||
commandPrefixList: List<String> = listOf("/mute"), // 默认命令前缀
|
private val adminsId: List<Long> = listOf(),
|
||||||
|
muteCommandPrefixList: List<String> = listOf("mute"), // 默认命令前缀
|
||||||
|
unmuteCommandPrefixList: List<String> = listOf("unmute"),
|
||||||
private val minBanMinutes: Int = 1,
|
private val minBanMinutes: Int = 1,
|
||||||
private val maxBanMinutes: Int = 15
|
private val maxBanMinutes: Int = 15,
|
||||||
|
private val factorX: Int = 2, // 系数 x,禁言倍数
|
||||||
|
|
||||||
) : BaseModule("BanModule", moduleName), PersistentState<BanModule.BanState> {
|
) : BaseModule("BanModule", moduleName), PersistentState<BanModule.BanState> {
|
||||||
|
|
||||||
private val commandParser = CommandParser(commandPrefixList)
|
private val banCommandParse = CommandParser(muteCommandPrefixList)
|
||||||
private val commandFilter = CommandFilter(commandParser)
|
private val pardonCommandParse = CommandParser(unmuteCommandPrefixList)
|
||||||
|
private val multiCommandFilter = MultiCommandFilter(listOf(banCommandParse, pardonCommandParse))
|
||||||
private val stateFile: File = getStateFileInternal("command_ban_state.json", name)
|
private val stateFile: File = getStateFileInternal("command_ban_state.json", name)
|
||||||
private val stateBackupFile: File = getStateFileInternal("command_ban_state.json.bak", name)
|
private val stateBackupFile: File = getStateFileInternal("command_ban_state.json.bak", name)
|
||||||
private var banState = loadState()
|
private var banState = loadState()
|
||||||
|
|
@ -44,7 +52,7 @@ class BanModule(
|
||||||
NewMessageFilter { userId ->
|
NewMessageFilter { userId ->
|
||||||
banState.getLastTriggerTime(userId) to banState.getLastTriggerRealId(userId)
|
banState.getLastTriggerTime(userId) to banState.getLastTriggerRealId(userId)
|
||||||
},
|
},
|
||||||
commandFilter
|
multiCommandFilter
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -75,6 +83,7 @@ class BanModule(
|
||||||
val filtered = triggerFilter.filter(messages)
|
val filtered = triggerFilter.filter(messages)
|
||||||
for (msg in filtered) {
|
for (msg in filtered) {
|
||||||
processBanCommand(msg)
|
processBanCommand(msg)
|
||||||
|
processUnBanCommand(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
@ -88,45 +97,160 @@ class BanModule(
|
||||||
seg.data.qq?.let { "@${it}" } ?: (seg.data.text ?: "")
|
seg.data.qq?.let { "@${it}" } ?: (seg.data.text ?: "")
|
||||||
}.trim()
|
}.trim()
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 从消息段中提取所有被 @ 的用户 ID
|
||||||
|
*/
|
||||||
|
private fun GetFriendMsgHistoryEvent.SpecificMsg.getMentionedUserIds(): List<ID> {
|
||||||
|
return this.message
|
||||||
|
.filter { it.type == MessageType.At && it.data.qq != null }
|
||||||
|
.mapNotNull { it.data.qq }
|
||||||
|
.distinctBy {
|
||||||
|
when (it) {
|
||||||
|
is ID.StringValue -> it.value
|
||||||
|
is ID.LongValue -> it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private suspend fun processUnBanCommand(msg: GetFriendMsgHistoryEvent.SpecificMsg) {
|
||||||
|
try {
|
||||||
|
pardonCommandParse.parseCommand(msg.plainText()) ?: return
|
||||||
|
// 获取所有被 @ 的用户
|
||||||
|
val mentionedUserIds = msg.getMentionedUserIds().map {
|
||||||
|
when (it) {
|
||||||
|
is ID.StringValue -> it.value.toLong()
|
||||||
|
is ID.LongValue -> it.value
|
||||||
|
}
|
||||||
|
} // List<Long>
|
||||||
|
val send =
|
||||||
|
napCatClient.send<GetGroupShutListEvent>(GetGroupShutListRequest(ID.long(groupMessagePollingModule.targetGroupId)))
|
||||||
|
val muteList = send.data.map { it.uin.toLong() }
|
||||||
|
for (target in mentionedUserIds) {
|
||||||
|
if(target !in muteList) {
|
||||||
|
sendGroupMessage("❌ 目标用户未被禁言",
|
||||||
|
msg.realId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
banUser(ID.long(target), groupMessagePollingModule.targetGroupId, 0)
|
||||||
|
sendGroupMessage(
|
||||||
|
"✅ 已解禁对方@(${target})",
|
||||||
|
msg.realId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新状态
|
||||||
|
banState = banState.updateLastTrigger(msg.userId, msg.realId, msg.time)
|
||||||
|
saveState(banState)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LoggerUtil.logger.error("[$name] 执行解禁言指令失败", e)
|
||||||
|
sendGroupMessage("❌ 执行解禁言失败,请检查解指令格式或权限", msg.realId)
|
||||||
|
banState = banState.updateLastTrigger(msg.sender.userId, msg.realId, msg.time)
|
||||||
|
saveState(banState)
|
||||||
|
}
|
||||||
|
}
|
||||||
private suspend fun processBanCommand(msg: GetFriendMsgHistoryEvent.SpecificMsg) {
|
private suspend fun processBanCommand(msg: GetFriendMsgHistoryEvent.SpecificMsg) {
|
||||||
try {
|
try {
|
||||||
val parsed = commandParser.parseCommand(msg.plainText()) ?: return
|
val parsed = banCommandParse.parseCommand(msg.plainText()) ?: return
|
||||||
val (command, argument) = parsed
|
val (_, argument) = parsed
|
||||||
|
|
||||||
// 参数格式: [分钟]
|
|
||||||
// 示例:/mute 5 → 自己禁言 5 分钟
|
|
||||||
// /mute → 自己随机禁言
|
|
||||||
val parts = argument.split(" ").filter { it.isNotBlank() }
|
val parts = argument.split(" ").filter { it.isNotBlank() }
|
||||||
|
|
||||||
|
// 解析禁言时间
|
||||||
val durationMinutes = parts.getOrNull(0)?.toIntOrNull()
|
val durationMinutes = parts.getOrNull(0)?.toIntOrNull()
|
||||||
?: Random.nextInt(minBanMinutes, maxBanMinutes + 1)
|
?: Random.nextInt(minBanMinutes, maxBanMinutes + 1)
|
||||||
val durationSeconds = durationMinutes.coerceIn(minBanMinutes, maxBanMinutes) * 60
|
val durationSeconds = durationMinutes.coerceIn(minBanMinutes, maxBanMinutes) * 60
|
||||||
|
|
||||||
val targetUserId = msg.sender.userId
|
// 获取所有被 @ 的用户
|
||||||
|
val mentionedUserIds = msg.getMentionedUserIds() // List<ID>
|
||||||
|
val targets = mentionedUserIds.ifEmpty { listOf(ID.long(msg.sender.userId)) }
|
||||||
|
|
||||||
banUser(targetUserId, groupMessagePollingModule.targetGroupId, durationSeconds)
|
for (target in targets) {
|
||||||
sendGroupMessage("✅ 你已被禁言 $durationMinutes 分钟", msg.realId)
|
val targetLongId = when (target) {
|
||||||
|
is ID.StringValue -> target.value.toLong()
|
||||||
|
is ID.LongValue -> target.value
|
||||||
|
}
|
||||||
|
|
||||||
// 更新状态(保证状态保存正确)
|
// 权限检查:非管理员不能禁言他人
|
||||||
// 禁言成功后更新状态
|
if (mentionedUserIds.isNotEmpty() && mentionedUserIds.size != 1 && msg.sender.userId !in adminsId) {
|
||||||
banState = banState.updateLastTrigger(targetUserId, msg.realId, msg.time)
|
sendGroupMessage("❌ 你没有权限禁言使用禁言多用户功能", msg.realId)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁言机器人跳过
|
||||||
|
if (targetLongId == selfId) {
|
||||||
|
sendGroupMessage("❌ 你没有权限禁言机器人", msg.realId)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (targetLongId in adminsId) {
|
||||||
|
sendGroupMessage("❌ 不支持禁言管理员", msg.realId)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单 @ 且非自己,可能触发反禁自己
|
||||||
|
if (mentionedUserIds.size == 1 && targetLongId != msg.sender.userId && msg.sender.userId !in adminsId) {
|
||||||
|
val dice = Random.nextInt(1, 7) // 1~6
|
||||||
|
val chance = when (dice) {
|
||||||
|
6 -> 100
|
||||||
|
5 -> 80
|
||||||
|
4 -> 60
|
||||||
|
3 -> 50
|
||||||
|
2 -> 20
|
||||||
|
1 -> 0
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val selfDuration = durationSeconds * factorX
|
||||||
|
if (Random.nextInt(100) < chance) {
|
||||||
|
// 触发反禁自己
|
||||||
|
banUser(ID.long(msg.sender.userId), groupMessagePollingModule.targetGroupId, selfDuration)
|
||||||
|
sendGroupMessage(
|
||||||
|
"⚠️ 骰子点数: $dice, 成功概率: ${chance}% → 失败,你触发了反禁,禁言 ${selfDuration / 60} 分钟",
|
||||||
|
msg.realId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// 未触发反禁自己,禁言目标
|
||||||
|
banUser(target, groupMessagePollingModule.targetGroupId, durationSeconds)
|
||||||
|
sendGroupMessage(
|
||||||
|
"✅ 骰子点数: $dice, 成功概率: ${chance}% → 成功禁言 <@${targetLongId}>",
|
||||||
|
msg.realId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 多 @ 或管理员操作,直接禁言目标
|
||||||
|
banUser(target, groupMessagePollingModule.targetGroupId, durationSeconds)
|
||||||
|
sendGroupMessage(
|
||||||
|
if (targetLongId == msg.sender.userId) {
|
||||||
|
"✅ 你已被禁言 ${durationSeconds/ 60} 分钟"
|
||||||
|
} else {
|
||||||
|
"✅ 已禁言 <@${targetLongId}> ${durationSeconds/ 60} 分钟"
|
||||||
|
},
|
||||||
|
msg.realId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
// 更新状态
|
||||||
|
banState = banState.updateLastTrigger(msg.userId, msg.realId, msg.time)
|
||||||
saveState(banState)
|
saveState(banState)
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
LoggerUtil.logger.error("[$name] 执行禁言指令失败", e)
|
LoggerUtil.logger.error("[$name] 执行禁言指令失败", e)
|
||||||
sendGroupMessage("❌ 执行禁言失败,请检查指令格式或权限", msg.realId)
|
sendGroupMessage("❌ 执行禁言失败,请检查指令格式或权限", msg.realId)
|
||||||
|
banState = banState.updateLastTrigger(msg.sender.userId, msg.realId, msg.time)
|
||||||
|
saveState(banState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private suspend fun banUser(userId: Long, groupId: Long, seconds: Int) {
|
|
||||||
|
private suspend fun banUser(userId: ID, groupId: Long, seconds: Int) {
|
||||||
val request = SetGroupBanRequest(
|
val request = SetGroupBanRequest(
|
||||||
duration = seconds.toDouble(),
|
duration = seconds.toDouble(),
|
||||||
groupId = ID.long(groupId),
|
groupId = ID.long(groupId),
|
||||||
userId = ID.long(userId)
|
userId = userId
|
||||||
)
|
)
|
||||||
napCatClient.sendUnit(request)
|
napCatClient.sendUnit(request)
|
||||||
LoggerUtil.logger.info("[$name] 已对用户 $userId 执行 $seconds 秒禁言")
|
LoggerUtil.logger.info("[$name] 已对用户 $userId 执行 $seconds 秒禁言")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun sendGroupMessage(text: String, replyTo: Long? = null) {
|
private suspend fun sendGroupMessage(text: String, replyTo: Long? = null) {
|
||||||
val request = SendGroupMsgRequest(
|
val request = SendGroupMsgRequest(
|
||||||
MessageElement.reply(ID.long(replyTo ?: 0), text),
|
MessageElement.reply(ID.long(replyTo ?: 0), text),
|
||||||
|
|
@ -136,20 +260,36 @@ class BanModule(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun info(): String {
|
override fun info(): String {
|
||||||
return "[$name] 指令禁言模块:用户发送 ${commandParser.getCommands().joinToString("、")} 来禁言自己," +
|
return buildString {
|
||||||
"支持指定分钟数或随机分钟数,范围 $minBanMinutes-$maxBanMinutes 分钟。"
|
append("[$name] 指令禁言模块:\n")
|
||||||
|
append(" - 用户发送 ${banCommandParse.getCommands().joinToString("、")} 来禁言自己或指定其他用户(需管理员权限)。\n")
|
||||||
|
append(" - 支持指定禁言分钟数或随机分钟数,范围 $minBanMinutes-$maxBanMinutes 分钟。\n")
|
||||||
|
append(" - 支持对单个 @ 用户禁言,有概率反禁自己(骰子点数决定概率)。\n")
|
||||||
|
append(" - 管理员可以禁言其他用户;非管理员尝试多个禁言对象会收到无权限提示。\n")
|
||||||
|
append(" - 用户发送 ${pardonCommandParse.getCommands().joinToString("、")} 来解禁指定用户。\n")
|
||||||
|
append(" - 仅支持对单个 @ 用户解禁言。\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun help(): String {
|
override fun help(): String {
|
||||||
return buildString {
|
return buildString {
|
||||||
appendLine("📖 [$name] 使用帮助:")
|
appendLine("📖 [$name] 使用帮助:")
|
||||||
appendLine(" - ${commandParser.getCommands().joinToString("、")} [分钟]")
|
appendLine("指令格式:${banCommandParse.getCommands().joinToString("、")} [分钟] [@用户...]")
|
||||||
appendLine(" · 不写分钟数 → 随机禁言 (范围 $minBanMinutes-$maxBanMinutes 分钟)")
|
|
||||||
appendLine(" · 写分钟数 → 自己禁言指定分钟数")
|
|
||||||
appendLine()
|
|
||||||
appendLine("示例:")
|
appendLine("示例:")
|
||||||
appendLine(" - /mute → 随机禁言自己")
|
appendLine(" - <指令> → 随机禁言自己")
|
||||||
appendLine(" - /mute 5 → 禁言自己 5 分钟")
|
appendLine(" - <指令> 5 → 禁言自己 5 分钟")
|
||||||
|
appendLine(" - <指令> 4 @User123 → 禁言指定用户 4 分钟(可能失败)")
|
||||||
|
appendLine(" - <指令> 4 @User123 @User22 → 禁言指定多用户 4 分钟(需在程序管理员列表中)")
|
||||||
|
appendLine()
|
||||||
|
appendLine("⚠️ 特殊说明:")
|
||||||
|
appendLine(" - 如果 @ 单个用户且执行者非需在程序管理员,有 y% 概率触发反禁自己,")
|
||||||
|
appendLine(" 骰子点数决定概率:6 → 100%, 5 → 80%, 4 → 60%, 3 → 50%, 2 → 20%, 1 → 0%")
|
||||||
|
appendLine(" - 禁言机器人自身不会生效")
|
||||||
|
appendLine(" - 禁言状态会自动保存以便下次使用")
|
||||||
|
appendLine()
|
||||||
|
appendLine("指令格式:${pardonCommandParse.getCommands().joinToString("、")} [@用户]")
|
||||||
|
appendLine("示例:")
|
||||||
|
appendLine(" - <指令> @User123 → 解禁指定用户")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package top.r3944realms.ltdmanager.module
|
||||||
|
|
||||||
|
class DGLabModule(
|
||||||
|
moduleName: String,
|
||||||
|
):
|
||||||
|
BaseModule("DGLabModule", moduleName) {
|
||||||
|
override fun onLoad() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onUnload() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -187,7 +187,7 @@ class ModGroupHandlerModule(
|
||||||
📝 尝试答案:
|
📝 尝试答案:
|
||||||
${ "\n" + record.reason.joinToString("\n") { " • $it" }}
|
${ "\n" + record.reason.joinToString("\n") { " • $it" }}
|
||||||
|
|
||||||
⚠️ 提示:请仔细阅读文档后再在群里提问,否则你会失去你的大脑🧠
|
⚠️ 提示:请仔细阅读群文档后再在群里提问,否则你会失去你的大脑🧠
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
} else {
|
} else {
|
||||||
"""
|
"""
|
||||||
|
|
@ -198,7 +198,7 @@ class ModGroupHandlerModule(
|
||||||
🔹 最终评分:SSS ⭐
|
🔹 最终评分:SSS ⭐
|
||||||
|
|
||||||
💡 该用户尚未有审核记录
|
💡 该用户尚未有审核记录
|
||||||
⚠️ 提示:请仔细阅读文档后再在群里提问,否则你会失去你的大脑🧠
|
⚠️ 提示:请仔细阅读群文档后再在群里提问,否则你会失去你的大脑🧠
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,11 @@ class RconPlayerListModule(
|
||||||
LoggerUtil.logger.error("[$name] RCON 查询失败", ex)
|
LoggerUtil.logger.error("[$name] RCON 查询失败", ex)
|
||||||
if (ex is TimeoutException) {
|
if (ex is TimeoutException) {
|
||||||
sendFailedMessage(napCatClient, msg.realId, msg.time, "⏳ RCON 连接超时")
|
sendFailedMessage(napCatClient, msg.realId, msg.time, "⏳ RCON 连接超时")
|
||||||
|
// ✅ 更新触发状态 & 持久化
|
||||||
|
lastTriggerState.lastTriggeredRealId = msg.realId
|
||||||
|
lastTriggerState.lastTriggerTime = msg.time
|
||||||
|
saveState(lastTriggerState)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
throw ex
|
throw ex
|
||||||
}.onSuccess { output ->
|
}.onSuccess { output ->
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ import top.r3944realms.ltdmanager.napcat.event.message.GetFriendMsgHistoryEvent
|
||||||
class KeywordFilter(private val keywords: Set<String>) : MessageFilter {
|
class KeywordFilter(private val keywords: Set<String>) : MessageFilter {
|
||||||
override suspend fun test(msg: GetFriendMsgHistoryEvent.SpecificMsg): Boolean {
|
override suspend fun test(msg: GetFriendMsgHistoryEvent.SpecificMsg): Boolean {
|
||||||
return msg.message.any { seg ->
|
return msg.message.any { seg ->
|
||||||
seg.type == MessageType.Text && seg.data.text?.let { it in keywords } == true
|
seg.type == MessageType.Text && seg.data.text?.let { text ->
|
||||||
|
keywords.any { keyword -> text.startsWith(keyword) }
|
||||||
|
} == true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package top.r3944realms.ltdmanager.module.common.filter.type
|
||||||
|
|
||||||
|
import top.r3944realms.ltdmanager.module.common.CommandParser
|
||||||
|
import top.r3944realms.ltdmanager.module.common.filter.MessageFilter
|
||||||
|
import top.r3944realms.ltdmanager.napcat.data.MessageType
|
||||||
|
import top.r3944realms.ltdmanager.napcat.event.message.GetFriendMsgHistoryEvent
|
||||||
|
|
||||||
|
/** 多命令解析器匹配 */
|
||||||
|
class MultiCommandFilter(private val parsers: List<CommandParser>) : MessageFilter {
|
||||||
|
override suspend fun test(msg: GetFriendMsgHistoryEvent.SpecificMsg): Boolean {
|
||||||
|
return msg.message.any { seg ->
|
||||||
|
seg.type == MessageType.Text && seg.data.text?.let { text ->
|
||||||
|
parsers.any { parser -> parser.containsCommand(text) }
|
||||||
|
} == true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package top.r3944realms.ltdmanager.utils
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat
|
||||||
|
import com.google.zxing.EncodeHintType
|
||||||
|
import com.google.zxing.MultiFormatWriter
|
||||||
|
import com.google.zxing.WriterException
|
||||||
|
import com.google.zxing.common.BitArray
|
||||||
|
import com.google.zxing.common.BitMatrix
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.util.*
|
||||||
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
|
object QRCodeUtil {
|
||||||
|
private const val CHARSET = "utf-8"
|
||||||
|
private const val FORMAT = "png"
|
||||||
|
@Throws(IOException::class, WriterException::class)
|
||||||
|
fun generateQRCode(string: String?): InputStream {
|
||||||
|
return generateQRCode(string, 256, 256)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class, WriterException::class)
|
||||||
|
fun generateQRCode(text: String?, width: Int, height: Int): ByteArrayInputStream {
|
||||||
|
val hints: MutableMap<EncodeHintType, Any> = EnumMap(EncodeHintType::class.java)
|
||||||
|
hints[EncodeHintType.CHARACTER_SET] = CHARSET
|
||||||
|
|
||||||
|
// 创建二维码编码器
|
||||||
|
val bitMatrix: BitMatrix =
|
||||||
|
MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints)
|
||||||
|
|
||||||
|
// 将BitMatrix转换为BufferedImage
|
||||||
|
val image = toBufferedImage(bitMatrix)
|
||||||
|
|
||||||
|
val outputStream = ByteArrayOutputStream()
|
||||||
|
ImageIO.write(image, FORMAT, outputStream)
|
||||||
|
|
||||||
|
return ByteArrayInputStream(outputStream.toByteArray()) // 返回 ByteArrayInputStream
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toBufferedImage(matrix: BitMatrix): BufferedImage {
|
||||||
|
val width: Int = matrix.width
|
||||||
|
val height: Int = matrix.height
|
||||||
|
val image = BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY)
|
||||||
|
val onColor = -0x1000000
|
||||||
|
val offColor = -0x1
|
||||||
|
val rowPixels = IntArray(width)
|
||||||
|
var row: BitArray = BitArray(width)
|
||||||
|
for (y in 0 until height) {
|
||||||
|
row = matrix.getRow(y, row)
|
||||||
|
for (x in 0 until width) {
|
||||||
|
rowPixels[x] = if (row.get(x)) onColor else offColor
|
||||||
|
}
|
||||||
|
image.setRGB(0, y, width, 1, rowPixels, 0, width)
|
||||||
|
}
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,4 +42,62 @@ blessing-skin-server:
|
||||||
path: "/api/invitation-codes/generate"
|
path: "/api/invitation-codes/generate"
|
||||||
# 格式为 ENC(XXX),若不是则会在加载完成配置后自动加密
|
# 格式为 ENC(XXX),若不是则会在加载完成配置后自动加密
|
||||||
encrypted-token: "your-secret-token"
|
encrypted-token: "your-secret-token"
|
||||||
|
dg-lab:
|
||||||
|
ws-server:
|
||||||
|
local-server-url: "0.0.0.0"
|
||||||
|
local-server-port: 4567
|
||||||
|
local-server-publish-url: "ws://127.0.0.1:4567"
|
||||||
|
local-server-secure: false
|
||||||
|
local-server-ssl-cert: "config/cert.p12"
|
||||||
|
local-server-ssl-key: "config/key.p12"
|
||||||
|
encrypted-local-server-ssl-password: "ENC(xxxxx)"
|
||||||
|
dg-lab-client:
|
||||||
|
bind-timeout: 90.0
|
||||||
|
register-timeout: 30.0
|
||||||
|
pulse-data:
|
||||||
|
custom-pulse-data: "data/dg-lab-play/customPulseData.json"
|
||||||
|
duration-per-post: 8.0
|
||||||
|
post-interval: 1.0
|
||||||
|
sleep-after-clear: 0.5
|
||||||
|
command-text:
|
||||||
|
append-pulse: "增加波形"
|
||||||
|
current-pulse: "当前波形"
|
||||||
|
current-strength: "当前强度"
|
||||||
|
decrease-strength: "减小强度"
|
||||||
|
dg-lab-device-join: "绑定郊狼"
|
||||||
|
exit-game: "退出游戏"
|
||||||
|
increase-strength: "加大强度"
|
||||||
|
random-pulse: "随机波形"
|
||||||
|
random-strength: "随机强度"
|
||||||
|
reset-pulse: "重置波形"
|
||||||
|
show-players: "当前玩家"
|
||||||
|
show-pulses: "可用波形"
|
||||||
|
usage: "郊狼玩法"
|
||||||
|
reply-text:
|
||||||
|
bind-timeout: "绑定超时"
|
||||||
|
current-players: "当前玩家:"
|
||||||
|
current-pulse: "当前波形循环为:【{}】"
|
||||||
|
current-strength: "A通道:{0}/{1} B通道:{2}/{3}"
|
||||||
|
failed-to-create-client: "创建 DG-Lab 控制终端失败"
|
||||||
|
failed-to-fetch-strength-info: "获取通道强度状态失败"
|
||||||
|
failed-to-fetch-strength-limit: "获取通道强度上限失败,控制失败"
|
||||||
|
game-exited: "已退出游戏"
|
||||||
|
invalid-pulse-param: "波形参数错误,控制失败"
|
||||||
|
invalid-strength-param: "强度参数错误,控制失败"
|
||||||
|
invalid-target: "目标玩家不存在或郊狼 App 未绑定"
|
||||||
|
no-available-pulse: "无可用波形"
|
||||||
|
no-player: "当前没有已连接的玩家,你可以绑定试试~"
|
||||||
|
not-bind-yet: "你目前没有绑定 DG-Lab App"
|
||||||
|
please-at-target: "使用命令的同时请 @ 想要控制的玩家"
|
||||||
|
please-scan-qrcode: "请用 DG-Lab App 扫描二维码以连接"
|
||||||
|
please-set-pulse-first: "请先设置郊狼波形:{}"
|
||||||
|
pulses-empty: "当前波形循环为空"
|
||||||
|
successfully-bind: "绑定成功,可以开始色色了!"
|
||||||
|
successfully-decreased: "郊狼强度减小了 {}%"
|
||||||
|
successfully-increased: "郊狼强度加强了 {}%!"
|
||||||
|
successfully-set-pulse: "郊狼波形成功设置为【{}】!"
|
||||||
|
successfully-set-to-strength: "郊狼强度成功设置为 {}%!"
|
||||||
|
debug:
|
||||||
|
enable-debug: false
|
||||||
|
ide-host: "127.0.0.1"
|
||||||
|
ide-port: 5678
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,39 @@
|
||||||
package top.r394realms.ltdmanagertest.help
|
package top.r394realms.ltdmanagertest.help
|
||||||
|
|
||||||
import top.r3944realms.ltdmanager.GlobalManager
|
import top.r3944realms.ltdmanager.GlobalManager
|
||||||
|
import top.r3944realms.ltdmanager.module.BanModule
|
||||||
|
import top.r3944realms.ltdmanager.module.GroupMessagePollingModule
|
||||||
|
import top.r3944realms.ltdmanager.module.HelpModule
|
||||||
|
|
||||||
fun main() = GlobalManager.runBlockingMain {
|
fun main() = GlobalManager.runBlockingMain {
|
||||||
|
val groupId:Long = 920719236
|
||||||
|
val selfQQId = 3327379836
|
||||||
|
val selfNickName = "闲趣老土豆"
|
||||||
|
// 创建模块实例
|
||||||
|
val groupMsgPollingModule = GroupMessagePollingModule(
|
||||||
|
moduleName = "TestGroup",
|
||||||
|
targetGroupId = groupId,
|
||||||
|
pollIntervalMillis = 5_000L,
|
||||||
|
msgHistoryCheck = 15
|
||||||
|
)
|
||||||
|
val helpModule = HelpModule(
|
||||||
|
moduleName = "TestGroup",
|
||||||
|
groupMessagePollingModule = groupMsgPollingModule,
|
||||||
|
selfId = selfQQId,
|
||||||
|
selfNickName = selfNickName,
|
||||||
|
)
|
||||||
|
val banModule = BanModule(
|
||||||
|
moduleName = "TestGroup",
|
||||||
|
groupMessagePollingModule = groupMsgPollingModule,
|
||||||
|
selfId = selfQQId,
|
||||||
|
adminsId = listOf(2561098830),
|
||||||
|
muteCommandPrefixList = listOf("禁言", "口球", "mute", "Mute", "闭嘴")
|
||||||
|
)
|
||||||
|
GlobalManager.moduleManager.registerModule(groupMsgPollingModule)
|
||||||
|
GlobalManager.moduleManager.registerModule(helpModule)
|
||||||
|
GlobalManager.moduleManager.registerModule(banModule)
|
||||||
|
|
||||||
|
GlobalManager.moduleManager.loadModule(groupMsgPollingModule.name)
|
||||||
|
GlobalManager.moduleManager.loadModule(helpModule.name)
|
||||||
|
GlobalManager.moduleManager.loadModule(banModule.name)
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
package top.r394realms.ltdmanagertest.mod
|
package top.r394realms.ltdmanagertest.mod
|
||||||
|
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import top.r3944realms.ltdmanager.GlobalManager
|
import top.r3944realms.ltdmanager.GlobalManager
|
||||||
|
import top.r3944realms.ltdmanager.GlobalManager.napCatClient
|
||||||
import top.r3944realms.ltdmanager.module.ModGroupHandlerModule
|
import top.r3944realms.ltdmanager.module.ModGroupHandlerModule
|
||||||
|
import top.r3944realms.ltdmanager.napcat.data.ID
|
||||||
|
import top.r3944realms.ltdmanager.napcat.data.MessageType
|
||||||
|
import top.r3944realms.ltdmanager.napcat.request.message.SendForwardMsgRequest
|
||||||
|
|
||||||
|
|
||||||
fun main() = GlobalManager.runBlockingMain {
|
fun main() = GlobalManager.runBlockingMain {
|
||||||
|
|
@ -22,4 +27,4 @@ fun main() = GlobalManager.runBlockingMain {
|
||||||
|
|
||||||
// 加载模块
|
// 加载模块
|
||||||
GlobalManager.moduleManager.loadModule(modGroupHandlerModule.name)
|
GlobalManager.moduleManager.loadModule(modGroupHandlerModule.name)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,85 @@
|
||||||
package top.r394realms.ltdmanagertest.msg
|
package top.r394realms.ltdmanagertest.msg
|
||||||
|
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import top.r3944realms.ltdmanager.GlobalManager
|
import top.r3944realms.ltdmanager.GlobalManager
|
||||||
|
import top.r3944realms.ltdmanager.module.ModGroupHandlerModule
|
||||||
import top.r3944realms.ltdmanager.napcat.NapCatClient
|
import top.r3944realms.ltdmanager.napcat.NapCatClient
|
||||||
import top.r3944realms.ltdmanager.napcat.data.ID
|
import top.r3944realms.ltdmanager.napcat.data.ID
|
||||||
import top.r3944realms.ltdmanager.napcat.data.MessageElement
|
import top.r3944realms.ltdmanager.napcat.data.MessageType
|
||||||
import top.r3944realms.ltdmanager.napcat.request.other.SendGroupMsgRequest
|
import top.r3944realms.ltdmanager.napcat.request.message.SendForwardMsgRequest
|
||||||
|
|
||||||
fun main() = GlobalManager.runBlockingMain {
|
fun main() = GlobalManager.runBlockingMain {
|
||||||
val napCatClient = NapCatClient.create()
|
val napCatClient = NapCatClient.create()
|
||||||
|
formatAndSendForwardMessage(napCatClient, 2561098830L, "幸福亮亮")
|
||||||
// 生成9x9乘法表字符串
|
}
|
||||||
val multiplicationTable = buildString {
|
private suspend fun formatAndSendForwardMessage(napCatClient: NapCatClient ,userId: Long, requesterNick: String) {
|
||||||
for (i in 1..9) {
|
// 虚拟数据 - 模拟有审核记录的情况
|
||||||
for (j in 1..i) {
|
val virtualRecord = ModGroupHandlerModule.RejectRecord(
|
||||||
append("$j×$i=${i * j}\t")
|
userId = userId,
|
||||||
}
|
reason = mutableListOf(
|
||||||
appendLine() // 换行
|
"模组作者是张三",
|
||||||
}
|
"作者是李四",
|
||||||
}
|
"制作人是王五",
|
||||||
|
"我不知道",
|
||||||
// 生成对齐检查字符
|
"可能是赵六吧"
|
||||||
val alignmentCheck = buildString {
|
),
|
||||||
appendLine("📏 对齐检查(每个数字占位):")
|
rejectCount = 5
|
||||||
appendLine("1234567890") // 数字标尺
|
|
||||||
appendLine("─".repeat(20)) // 分隔线
|
|
||||||
|
|
||||||
for (i in 1..9) {
|
|
||||||
for (j in 1..i) {
|
|
||||||
val product = i * j
|
|
||||||
val placeholder = "X".repeat("$j×$i=$product".length)
|
|
||||||
append("$placeholder\t")
|
|
||||||
}
|
|
||||||
appendLine()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
napCatClient.sendUnit(
|
|
||||||
SendGroupMsgRequest(
|
|
||||||
listOf(
|
|
||||||
MessageElement.at(ID.long(2561098830), "幸福亮亮"),
|
|
||||||
MessageElement.text("\n"),
|
|
||||||
MessageElement.text("9×9乘法表:\n"),
|
|
||||||
MessageElement.text(multiplicationTable),
|
|
||||||
MessageElement.text("\n────────────────────\n"),
|
|
||||||
MessageElement.text(alignmentCheck),
|
|
||||||
MessageElement.text("\n提问前,请看文档,不看文档就提问直接肘击(")
|
|
||||||
),
|
|
||||||
ID.long(339340846)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 虚拟数据 - 模拟无审核记录的情况(注释掉下面这行来测试)
|
||||||
|
// val virtualRecord = null
|
||||||
|
|
||||||
|
val record = virtualRecord
|
||||||
|
val content = """
|
||||||
|
📊 用户审核记录
|
||||||
|
──────────────────
|
||||||
|
🔹 用户QQ号:${record.userId}
|
||||||
|
🔹 尝试次数:${record.rejectCount}
|
||||||
|
🔹 最终评分:${rate(record.rejectCount)}
|
||||||
|
|
||||||
|
📝 尝试答案:
|
||||||
|
${"\n" + record.reason.joinToString("\n") { " • $it" }}
|
||||||
|
|
||||||
|
⚠️ 提示:请仔细阅读文档后再在群里提问,否则你会失去你的大脑🧠
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
// 创建合并转发消息
|
||||||
|
val forwardRequest = SendForwardMsgRequest(
|
||||||
|
groupId = ID.long(339340846),
|
||||||
|
messages = listOf(
|
||||||
|
SendForwardMsgRequest.TopForwardMsg(
|
||||||
|
data = SendForwardMsgRequest.MessageData(
|
||||||
|
content = listOf(
|
||||||
|
SendForwardMsgRequest.Message(
|
||||||
|
data = SendForwardMsgRequest.PurpleData(
|
||||||
|
text = content
|
||||||
|
),
|
||||||
|
type = MessageType.Text
|
||||||
|
)
|
||||||
|
),
|
||||||
|
nickname = "审核系统",
|
||||||
|
userId = ID.long(0) // 系统ID
|
||||||
|
),
|
||||||
|
type = MessageType.Text
|
||||||
|
)
|
||||||
|
),
|
||||||
|
news = listOf(
|
||||||
|
SendForwardMsgRequest.ForwardModelNews("用户审核记录详情")
|
||||||
|
),
|
||||||
|
prompt = "📋 ${requesterNick}入群审核评分${rate(record.rejectCount ?: 0)}",
|
||||||
|
source = "审核系统",
|
||||||
|
summary = "点击查看用户 $requesterNick 的审核详情"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 发送合并转发消息
|
||||||
|
napCatClient.sendUnit(forwardRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rate(count: Int): String = when (count) {
|
||||||
|
0 -> "SSS"
|
||||||
|
1 -> "A"
|
||||||
|
2 -> "B"
|
||||||
|
3 -> "C"
|
||||||
|
4 -> "D"
|
||||||
|
else -> "F"
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user