init & finish
This commit is contained in:
commit
42b584a123
|
|
@ -0,0 +1,8 @@
|
|||
### Idea Gradle template
|
||||
### IDEA ###
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
### Gradle ###
|
||||
.gradle
|
||||
build
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# BiliInviteCode
|
||||
|
||||
BiliInviteCode - 邀请制入服检测
|
||||
|
||||
服务器会在启动后自动检测是否需要转换, 转换自动进行.
|
||||
|
||||
## 命令
|
||||
|
||||
主命令: inviteCode/icode/code/ic
|
||||
|
||||
子命令:
|
||||
|
||||
- /inviteCode use <邀请码> 激活邀请码 √
|
||||
|
||||
- /inviteCode generate <数量> 生成指定数量的激活码 (后台) √
|
||||
|
||||
激活码会被保存在`服务器根目录/plugins/BiliInviteCode/InviteCode/generated/xx.txt`
|
||||
|
||||
- /inviteCode edit <玩家ID> <新的QQ号> 修改激活码对应的值 (后台) √
|
||||
|
||||
- /inviteCode remove <激活码> 移除该激活码
|
||||
|
||||
- /inviteCode current 显示所有可用激活码
|
||||
|
||||
- /inviteCode add <激活码> 手动创建激活码 (后台) √
|
||||
|
||||
激活码的长度不能长于24位
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.6.10"
|
||||
id("io.izzel.taboolib") version "1.34"
|
||||
}
|
||||
|
||||
val exposedVersion: String by project
|
||||
|
||||
group = "cc.maxmc.invite"
|
||||
version = "1.1.0"
|
||||
|
||||
taboolib {
|
||||
description {
|
||||
contributors {
|
||||
name("TONY_All")
|
||||
}
|
||||
}
|
||||
options("skip-kotlin-relocate")
|
||||
|
||||
install("common")
|
||||
install("platform-bukkit")
|
||||
version = "6.0.7-26"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("ink.ptms.core:v11605:11605")
|
||||
compileOnly(kotlin("stdlib"))
|
||||
compileOnly(fileTree("libs"))
|
||||
implementation("org.jetbrains.exposed:exposed-core:$exposedVersion")
|
||||
implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion")
|
||||
implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "16"
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
kotlin.code.style=official
|
||||
exposedVersion=0.37.3
|
||||
Binary file not shown.
|
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
rootProject.name = "BiliInviteCode"
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package cc.maxmc.invite
|
||||
|
||||
import cc.maxmc.invite.command.InviteCodeCommands
|
||||
import cc.maxmc.invite.data.initDatabase
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import org.bukkit.Bukkit
|
||||
import taboolib.common.env.RuntimeDependencies
|
||||
import taboolib.common.env.RuntimeDependency
|
||||
import taboolib.common.platform.Plugin
|
||||
import taboolib.common.platform.function.console
|
||||
import taboolib.platform.BukkitPlugin
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
@RuntimeDependencies(
|
||||
RuntimeDependency("org.jetbrains.exposed:exposed-core:0.37.3"),
|
||||
RuntimeDependency("org.jetbrains.exposed:exposed-dao:0.37.3"),
|
||||
RuntimeDependency("org.jetbrains.exposed:exposed-jdbc:0.37.3"),
|
||||
RuntimeDependency("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"),
|
||||
RuntimeDependency("com.h2database:h2:1.4.200")
|
||||
)
|
||||
object BiliInviteCode : Plugin() {
|
||||
override fun onEnable() {
|
||||
initDatabase()
|
||||
InviteCodeCommands
|
||||
// cc.maxmc.invite.command.DebugCommands.debug()
|
||||
}
|
||||
}
|
||||
|
||||
val bukkitSyncContext = Executor {
|
||||
Bukkit.getScheduler().runTask(BukkitPlugin.getInstance(), it)
|
||||
}.asCoroutineDispatcher()
|
||||
|
||||
val bukkitAsyncContext = Executor {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(BukkitPlugin.getInstance(), it)
|
||||
}.asCoroutineDispatcher()
|
||||
|
||||
val PluginScope = CoroutineScope(bukkitAsyncContext + SupervisorJob() + CoroutineExceptionHandler { _, except ->
|
||||
console().sendMessage("§e执行异步操作时出现异常 ${except.message}")
|
||||
console().sendMessage("§c栈追踪: ")
|
||||
except.stackTrace.forEach {
|
||||
console().sendMessage("§c位于 $it")
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
package cc.maxmc.invite.command
|
||||
|
||||
import cc.maxmc.invite.PluginScope
|
||||
import cc.maxmc.invite.concurrent.chatInput
|
||||
import cc.maxmc.invite.data.InviteCode
|
||||
import cc.maxmc.invite.data.InviteCodes
|
||||
import cc.maxmc.invite.listener.InvitedListener
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.ConsoleCommandSender
|
||||
import org.bukkit.entity.Player
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import taboolib.common.platform.command.CommandBuilder
|
||||
import taboolib.common.platform.command.command
|
||||
import taboolib.common.platform.function.getDataFolder
|
||||
import taboolib.common.platform.function.info
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
object InviteCodeCommands {
|
||||
init {
|
||||
command("inviteCode", aliases = listOf("code", "icode", "ic")) {
|
||||
cmdUse()
|
||||
cmdGenerate()
|
||||
cmdEdit()
|
||||
cmdAdd()
|
||||
cmdRemove()
|
||||
cmdCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
private fun CommandBuilder.CommandComponent.cmdUse() = literal("use") {
|
||||
tailrec suspend fun requireQQNumber(player: Player): String? {
|
||||
val input = chatInput(player, "§e| §7请输入您的QQ号进行绑定 (输入 §ecancel §7取消)")
|
||||
if (input == "cancel") return null
|
||||
if (input.length >= 10) return requireQQNumber(player)
|
||||
if (input.toLongOrNull() == null) return requireQQNumber(player)
|
||||
return input
|
||||
}
|
||||
|
||||
dynamic {
|
||||
execute<Player> { sender, _, argument ->
|
||||
if (!InvitedListener.cache.containsKey(sender.uniqueId)) return@execute sender.sendMessage("§e| §7您的账号已激活, 无需使用邀请码.")
|
||||
sender.sendMessage("§b| §7正在激活邀请码...")
|
||||
PluginScope.launch {
|
||||
val inviteCode = transaction {
|
||||
val inviteCode = InviteCode.find { InviteCodes.inviteCode eq argument }.firstOrNull()
|
||||
?: return@transaction let { sender.sendMessage("§c| §7该激活码不存在, 请重试."); null }
|
||||
if (inviteCode.name != null) return@transaction sender.sendMessage("§c| §7该邀请码已被激活, 请重试.")
|
||||
.let { null }
|
||||
return@transaction inviteCode
|
||||
} ?: return@launch
|
||||
val qqNum = requireQQNumber(sender) ?: return@launch sender.sendMessage("§e| §7已取消激活验证码.")
|
||||
sender.sendMessage("§a| §7该激活码成功绑定至QQ: §a${qqNum}")
|
||||
InvitedListener.cache.remove(sender.uniqueId)
|
||||
transaction {
|
||||
inviteCode.run {
|
||||
name = sender.name
|
||||
uid = sender.uniqueId
|
||||
qq = qqNum
|
||||
}
|
||||
sender.sendMessage("§a| §7成功激活邀请码.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CommandBuilder.CommandComponent.cmdGenerate() = literal("generate") {
|
||||
fun generateRandomString(length: Int): String {
|
||||
val availableChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||
val result = StringBuilder()
|
||||
repeat(length) {
|
||||
result.append(availableChars.random())
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
tailrec fun generateAvailableCode(): String {
|
||||
val result = "${generateRandomString(5)}-${generateRandomString(5)}-${generateRandomString(5)}-${
|
||||
generateRandomString(5)
|
||||
}"
|
||||
val exist = transaction {
|
||||
val exist = !InviteCode.find { InviteCodes.inviteCode eq result }.empty()
|
||||
if (!exist) {
|
||||
InviteCode.new {
|
||||
inviteCode = result
|
||||
}
|
||||
}
|
||||
return@transaction exist
|
||||
}
|
||||
return if (exist) generateAvailableCode() else result
|
||||
}
|
||||
|
||||
val format = SimpleDateFormat("yyyy-MM-dd")
|
||||
|
||||
dynamic {
|
||||
restrict<ConsoleCommandSender> { _, _, arg ->
|
||||
return@restrict arg.toIntOrNull() != null
|
||||
}
|
||||
execute<ConsoleCommandSender> { _, _, arg ->
|
||||
PluginScope.launch {
|
||||
info("§b| §7正在生成邀请码...")
|
||||
val generated = ArrayList<String>()
|
||||
repeat(arg.toInt()) {
|
||||
generated.add(generateAvailableCode())
|
||||
}
|
||||
val generateFolder = File(getDataFolder(), "generated")
|
||||
generateFolder.mkdirs()
|
||||
val count = generateFolder.listFiles()!!.filter {
|
||||
it.name.startsWith(format.format(Date()))
|
||||
}.size
|
||||
val target = File(generateFolder, "${format.format(Date())}-${count + 1}.txt")
|
||||
withContext(Dispatchers.IO) {
|
||||
target.createNewFile()
|
||||
target.writeText(generated.joinToString("\n"))
|
||||
}
|
||||
info("§a| §7成功生成 §a$arg §7个邀请码")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CommandBuilder.CommandComponent.cmdEdit() = literal("edit") {
|
||||
dynamic {
|
||||
restrict<ConsoleCommandSender> { _, _, arg ->
|
||||
!InviteCode.find { InviteCodes.name eq arg }.empty()
|
||||
}
|
||||
suggestion<ConsoleCommandSender> { sender, ctx ->
|
||||
return@suggestion Bukkit.getOnlinePlayers().map { it.name }
|
||||
}
|
||||
dynamic {
|
||||
restrict<ConsoleCommandSender> { _, _, arg ->
|
||||
arg.length <= 10 && arg.toLongOrNull() != null
|
||||
}
|
||||
execute<ConsoleCommandSender> { sender, ctx, arg ->
|
||||
PluginScope.launch {
|
||||
InviteCode.find { InviteCodes.name eq ctx.get(-1) }.first().run {
|
||||
qq = arg
|
||||
}
|
||||
sender.sendMessage("§a| §7修改成功")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CommandBuilder.CommandComponent.cmdAdd() = literal("add") {
|
||||
dynamic {
|
||||
execute<ConsoleCommandSender> { sender, _, arg ->
|
||||
PluginScope.launch {
|
||||
if (!InviteCode.find { InviteCodes.inviteCode eq arg }.empty()) {
|
||||
sender.sendMessage("§c| §7该邀请码已存在, 无法添加.")
|
||||
return@launch
|
||||
}
|
||||
InviteCode.new {
|
||||
inviteCode = arg
|
||||
}
|
||||
sender.sendMessage("§a| §7成功添加一个邀请码: §a$arg")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CommandBuilder.CommandComponent.cmdRemove() = literal("remove") {
|
||||
execute<ConsoleCommandSender> { sender, _, arg ->
|
||||
val findings = InviteCode.find { InviteCodes.inviteCode eq arg }
|
||||
if (findings.empty()) {
|
||||
sender.sendMessage("§e| §7该邀请码不存在, 无需删除.")
|
||||
}
|
||||
findings.first().delete()
|
||||
sender.sendMessage("§a| §7成功删除该邀请码.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun CommandBuilder.CommandComponent.cmdCurrent() = literal("current") {
|
||||
execute<ConsoleCommandSender> { sender, _, _ ->
|
||||
PluginScope.launch {
|
||||
val codes = ArrayList<String>(2000)
|
||||
InviteCode.find { InviteCodes.uid eq null }.forEach {
|
||||
codes.add(it.inviteCode)
|
||||
}
|
||||
val result = codes.joinToString("\n")
|
||||
val output = File(getDataFolder(), "current.txt")
|
||||
withContext(Dispatchers.IO) {
|
||||
output.mkdirs()
|
||||
output.createNewFile()
|
||||
output.writeText(result)
|
||||
}
|
||||
sender.sendMessage("现存可用邀请码已保存至plugins/BiliInviteCode/current.txt")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package cc.maxmc.invite.concurrent
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import taboolib.common.platform.event.SubscribeEvent
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
object ChatInputHandler {
|
||||
val inputting = ConcurrentHashMap<UUID, Continuation<String>>()
|
||||
|
||||
@SubscribeEvent
|
||||
fun onQuit(e: PlayerQuitEvent) {
|
||||
inputting.remove(e.player.uniqueId)?.resumeWithException(IllegalArgumentException("Player Quit Game!"))
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onChat(e: AsyncPlayerChatEvent) {
|
||||
inputting.remove(e.player.uniqueId)?.resume(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* require player to input something in chat
|
||||
*
|
||||
* @return Player Input
|
||||
*/
|
||||
suspend fun chatInput(player: Player, message: String): String = suspendCoroutine {
|
||||
player.sendMessage(message)
|
||||
ChatInputHandler.inputting[player.uniqueId] = it
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package cc.maxmc.invite.data
|
||||
|
||||
import cc.maxmc.invite.PluginScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import taboolib.common.platform.function.getDataFolder
|
||||
import taboolib.common.platform.function.info
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
fun convert() {
|
||||
val file = File("./plugins/InviteCode/config.yml")
|
||||
info("§b| §7找到旧版配置文件, 正在转换...")
|
||||
if (!file.exists()) return
|
||||
val read = readFile(file)
|
||||
val usable = read.filter { it.value != null }
|
||||
.filter { it.value != "null" }
|
||||
.toList()
|
||||
.associate { it.first to it.second!! }
|
||||
PluginScope.launch {
|
||||
transaction {
|
||||
usable.forEach { (code, player) ->
|
||||
val uuid = Bukkit.getOfflinePlayer(player).uniqueId
|
||||
InviteCode.new {
|
||||
inviteCode = code
|
||||
uid = uuid
|
||||
name = player
|
||||
}
|
||||
}
|
||||
}
|
||||
info("§a| §7转换成功!")
|
||||
withContext(Dispatchers.IO) {
|
||||
Files.move(file.toPath(), File(getDataFolder(), "legacy.yml.deprecated").toPath())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun readFile(file: File): Map<String, String?> {
|
||||
val config = YamlConfiguration.loadConfiguration(file)
|
||||
return config.getMapList("invite-code")
|
||||
.associate {
|
||||
try {
|
||||
val player = it["player"] as String?
|
||||
it.remove("player")
|
||||
val code = it.values.first() as String
|
||||
code to player
|
||||
} catch (e: Exception) {
|
||||
println("§e| §7一条数据转换失败, 正在忽略...")
|
||||
println(e.message)
|
||||
"" to "null"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package cc.maxmc.invite.data
|
||||
|
||||
import cc.maxmc.invite.PluginScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.bukkit.Bukkit
|
||||
import org.jetbrains.exposed.dao.IntEntity
|
||||
import org.jetbrains.exposed.dao.IntEntityClass
|
||||
import org.jetbrains.exposed.dao.id.EntityID
|
||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.SchemaUtils
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import taboolib.common.platform.function.getDataFolder
|
||||
import taboolib.common.platform.function.info
|
||||
import taboolib.common.platform.function.warning
|
||||
import taboolib.platform.BukkitPlugin
|
||||
import java.io.File
|
||||
|
||||
fun initDatabase() {
|
||||
try {
|
||||
Database.connect("jdbc:h2:file:./${File(getDataFolder(), "data").toPath()}")
|
||||
info("§a| §7成功连接至内存数据库.")
|
||||
} catch (e: Exception) {
|
||||
warning("§c| §7连接至内存数据库时出现异常: ${e.message}")
|
||||
e.printStackTrace()
|
||||
Bukkit.getPluginManager().disablePlugin(BukkitPlugin.getInstance())
|
||||
}
|
||||
PluginScope.launch {
|
||||
transaction {
|
||||
info("§b| §7正在读取数据库信息...")
|
||||
SchemaUtils.create(InviteCodes)
|
||||
info("§a| §7成功读取数据库信息.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object InviteCodes : IntIdTable() {
|
||||
val inviteCode = varchar("invite_code", 24)
|
||||
val name = varchar("name", 100).nullable()
|
||||
val uid = uuid("player_uid").nullable()
|
||||
val qq = varchar("qq", 10).nullable()
|
||||
}
|
||||
|
||||
class InviteCode(id: EntityID<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<InviteCode>(InviteCodes)
|
||||
|
||||
var inviteCode by InviteCodes.inviteCode
|
||||
var name by InviteCodes.name
|
||||
var uid by InviteCodes.uid
|
||||
var qq by InviteCodes.qq
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package cc.maxmc.invite.listener
|
||||
|
||||
import cc.maxmc.invite.PluginScope
|
||||
import cc.maxmc.invite.data.InviteCode
|
||||
import cc.maxmc.invite.data.InviteCodes
|
||||
import kotlinx.coroutines.launch
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.event.player.*
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import taboolib.common.platform.event.SubscribeEvent
|
||||
import taboolib.common.platform.function.console
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object InvitedListener {
|
||||
val cache = ConcurrentHashMap<UUID, Location>()
|
||||
|
||||
@SubscribeEvent
|
||||
fun onMove(e: PlayerMoveEvent) {
|
||||
if (!cache.containsKey(e.player.uniqueId)) return
|
||||
if (e.player.location.distance(cache[e.player.uniqueId]!!) > 5) {
|
||||
e.player.teleport(cache[e.player.uniqueId]!!)
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onInteract(e: PlayerInteractEvent) {
|
||||
if (!cache.containsKey(e.player.uniqueId)) return
|
||||
e.isCancelled = true
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onChat(e: AsyncPlayerChatEvent) {
|
||||
if (!cache.containsKey(e.player.uniqueId)) return
|
||||
e.isCancelled = true
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onCommand(e: PlayerCommandPreprocessEvent) {
|
||||
if (!cache.containsKey(e.player.uniqueId)) return
|
||||
if (!(e.message.startsWith("/ic")
|
||||
|| e.message.startsWith("/icode")
|
||||
|| e.message.startsWith("/code")
|
||||
|| e.message.startsWith("/inviteCode", ignoreCase = true))
|
||||
) return run { e.isCancelled = true }
|
||||
if (!e.message.contains("use")) e.isCancelled = true
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onJoin(e: PlayerJoinEvent) {
|
||||
cache[e.player.uniqueId] = e.player.location
|
||||
e.player.sendMessage("§e| §7正在检查您的邀请码...请稍等.")
|
||||
PluginScope.launch {
|
||||
transaction {
|
||||
val playerInviteCode = InviteCode.find { InviteCodes.uid eq e.player.uniqueId }
|
||||
.firstOrNull()
|
||||
?: return@transaction e.player.sendMessage("§c| §7您的账号未激活, 请输入 §c/ic use <激活码> §7来进行激活.")
|
||||
e.player.sendMessage("§a| §7检查通过, 您可以正常进行游戏.")
|
||||
cache.remove(e.player.uniqueId)
|
||||
val lastName = playerInviteCode.name
|
||||
if (lastName != e.player.name) {
|
||||
e.player.sendMessage("§e| §7由于正版ID变更, 您的ID已自动修改.")
|
||||
console().sendMessage("§e| §7玩家(${e.player.uniqueId})的ID已由 §e${lastName} §7修改为 §e${e.player.name}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package cc.maxmc.invite.command
|
||||
|
||||
import cc.maxmc.invite.data.InviteCode
|
||||
import cc.maxmc.invite.data.InviteCodes
|
||||
import org.jetbrains.exposed.sql.SchemaUtils
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
object DebugCommands {
|
||||
fun debug() {
|
||||
taboolib.common.platform.function.console().sendMessage("§c|")
|
||||
taboolib.common.platform.function.console().sendMessage("§c|")
|
||||
taboolib.common.platform.function.console().sendMessage("§c|")
|
||||
taboolib.common.platform.function.console().sendMessage("§c| DEBUG 模式已开启!")
|
||||
taboolib.common.platform.function.console().sendMessage("§c|")
|
||||
taboolib.common.platform.function.console().sendMessage("§c|")
|
||||
taboolib.common.platform.function.console().sendMessage("§c|")
|
||||
|
||||
taboolib.common.platform.command.command("idebug") {
|
||||
literal("clean") {
|
||||
execute<org.bukkit.entity.Player> { sender, _, _ ->
|
||||
transaction {
|
||||
SchemaUtils.drop(InviteCodes)
|
||||
SchemaUtils.create(InviteCodes)
|
||||
sender.sendMessage("§a| §7成功清空数据库")
|
||||
}
|
||||
}
|
||||
}
|
||||
literal("rename") {
|
||||
dynamic {
|
||||
execute<org.bukkit.entity.Player> { sender, _, arg ->
|
||||
transaction {
|
||||
InviteCode.find { InviteCodes.uid eq sender.uniqueId }.first().run {
|
||||
name = arg
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue