Skip to content

Commit

Permalink
feat: Add tpa command, test command callback
Browse files Browse the repository at this point in the history
  • Loading branch information
half-nothing committed Sep 18, 2024
1 parent ec3a421 commit abf6b16
Show file tree
Hide file tree
Showing 16 changed files with 238 additions and 61 deletions.
1 change: 1 addition & 0 deletions src/main/kotlin/net/superricky/tpaplusplus/GlobalConst.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ object GlobalConst {
const val CONFIG_FOLDER_PATH = MOD_ID
const val CONFIG_FILE_NAME = "$MOD_ID.toml"
const val CONFIG_FILE_PATH = "$CONFIG_FOLDER_PATH/$CONFIG_FILE_NAME"
const val NETHER_COEFFICIENT = 8
const val GITHUB_URL = "https://github.com/SuperRicky14/TpaPlusPlus"
const val MODRINTH_URL = "https://modrinth.com/mod/tpa++"
const val COURSE_FORGE_URL = "https://www.curseforge.com/minecraft/mc-mods/tpaplusplus"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,38 @@ package net.superricky.tpaplusplus.async

import kotlinx.atomicfu.AtomicBoolean
import kotlinx.atomicfu.atomic
import net.superricky.tpaplusplus.config.AdvancedSpec
import net.superricky.tpaplusplus.config.CommonSpec
import net.superricky.tpaplusplus.config.Config
import net.superricky.tpaplusplus.request.Request
import net.superricky.tpaplusplus.utility.LevelBoundVec3
import net.superricky.tpaplusplus.utility.AsyncCommandResult
import net.superricky.tpaplusplus.utility.LevelBoundVec3
import net.superricky.tpaplusplus.utility.translateSecondToTick
import net.superricky.tpaplusplus.utility.translateTickToSecond

class AsyncCommandData(
private val request: Request,
private val pos: LevelBoundVec3,
val callback: Function1<AsyncCommandResult, Void>
private var delay: Double,
private val callback: Function2<AsyncCommandResult, Request, Unit>
) {
private var canceled: AtomicBoolean = atomic(false)
private var timeout = 0L
private var afterDelay: Boolean = false

init {
timeout = Config.getConfig()[CommonSpec.tpaTimeout].toLong()
if (Config.getConfig()[AdvancedSpec.unblockingTickLoop]) {
timeout *= Config.getConfig()[AdvancedSpec.asyncLoopRate]
} else {
@Suppress("MagicNumber")
timeout *= 20
}
timeout = Config.getConfig()[CommonSpec.tpaTimeout].toLong().translateSecondToTick()
delay = delay.translateTickToSecond()
}

fun tick(): Boolean {
if (delay > 0) {
delay--
return false
}
if (!afterDelay) {
afterDelay = true
call(AsyncCommandResult.AFTER_DELAY)
}
timeout--
return timeout <= 0
}
Expand All @@ -38,6 +44,10 @@ class AsyncCommandData(

fun isCanceled(): Boolean = canceled.value

fun call(commandResult: AsyncCommandResult) {
callback.invoke(commandResult, request)
}

fun cancel() {
canceled.value = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,19 @@ object AsyncCommandHelper : CoroutineScope {
requests.forEach {
// check canceled
if (it.isCanceled()) {
it.callback.invoke(AsyncCommandResult.BE_CANCELED)
it.call(AsyncCommandResult.BE_CANCELED)
elementRemoved.add(it)
return@forEach
}
// check distance
if (!checkActions[it.getRequest().commandType]!!.invoke(it)) {
it.callback.invoke(AsyncCommandResult.OUT_OF_DISTANCE)
it.call(AsyncCommandResult.OUT_OF_DISTANCE)
elementRemoved.add(it)
return@forEach
}
// check timeout
if (it.tick()) {
it.callback.invoke(AsyncCommandResult.TIMEOUT)
it.call(AsyncCommandResult.TIMEOUT)
elementRemoved.add(it)
return@forEach
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package net.superricky.tpaplusplus.command

import net.minecraft.command.argument.EntityArgumentType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
import net.superricky.tpaplusplus.utility.CommandResult
import net.superricky.tpaplusplus.utility.Context

object CommandHelper {
fun checkSenderReceiver(
context: Context,
checker: Function2<ServerPlayerEntity?, ServerPlayerEntity?, CommandResult> = this::checkSenderReceiver,
): Triple<CommandResult, ServerPlayerEntity?, ServerPlayerEntity?> {
val source = context.source
val sender = source.player
val receiver = EntityArgumentType.getPlayer(context, "player")
val result = checker.invoke(sender, receiver)
return when (result) {
CommandResult.SELF_CHECK_ERROR -> {
source.sendError(Text.translatable("command.error.self"))
Triple(CommandResult.SELF_CHECK_ERROR, null, null)
}

CommandResult.SENDER_NOT_EXIST -> {
source.sendError(Text.translatable("command.error.sender.not_exist"))
Triple(CommandResult.SENDER_NOT_EXIST, null, null)
}

CommandResult.RECEIVER_NOT_EXIST -> {
source.sendError(Text.translatable("command.error.target.not_exist"))
Triple(CommandResult.RECEIVER_NOT_EXIST, null, null)
}

CommandResult.NORMAL -> {
Triple(CommandResult.NORMAL, sender, receiver)
}
}
}

fun checkSender(sender: ServerPlayerEntity?, ignored: ServerPlayerEntity?): CommandResult {
sender ?: return CommandResult.SENDER_NOT_EXIST
return CommandResult.NORMAL
}

fun checkSenderReceiver(sender: ServerPlayerEntity?, receiver: ServerPlayerEntity?): CommandResult {
sender ?: return CommandResult.SENDER_NOT_EXIST
receiver ?: return CommandResult.RECEIVER_NOT_EXIST
if (sender == receiver) {
return CommandResult.SELF_CHECK_ERROR
}
return CommandResult.NORMAL
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import net.superricky.tpaplusplus.TpaPlusPlus
import net.superricky.tpaplusplus.async.AsyncCommandData
import net.superricky.tpaplusplus.command.AsyncCommand
import net.superricky.tpaplusplus.command.BuildableCommand
import net.superricky.tpaplusplus.command.CommandHelper.checkSenderReceiver
import net.superricky.tpaplusplus.config.CommonSpec
import net.superricky.tpaplusplus.config.Config
import net.superricky.tpaplusplus.config.command.CommandDistanceSpec
Expand All @@ -34,20 +35,10 @@ object BlockCommand : BuildableCommand, AsyncCommand {

private fun blockPlayer(context: Context): Int {
val source = context.source
val sender = source.player
val target = EntityArgumentType.getPlayer(context, "player")
if (sender == null) {
source.sendError(Text.translatable("command.error.sender.not_exist"))
return CommandResult.SENDER_NOT_EXIST.status
}
if (target == null) {
source.sendError(Text.translatable("command.error.target.not_exist"))
return CommandResult.TARGET_NOT_EXIST.status
}
if (sender == target) {
source.sendError(Text.translatable("command.block.error.self"))
return CommandResult.SELF_CHECK_ERROR.status
}
val (result, sender, target) = checkSenderReceiver(context)
if (result != CommandResult.NORMAL) return result.status
sender!!
target!!
TpaPlusPlus.launch {
if (DatabaseManager.insertBlockedPlayer(sender.uuid, target.uuid)) {
source.sendFeedback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import net.superricky.tpaplusplus.TpaPlusPlus
import net.superricky.tpaplusplus.async.AsyncCommandData
import net.superricky.tpaplusplus.command.AsyncCommand
import net.superricky.tpaplusplus.command.BuildableCommand
import net.superricky.tpaplusplus.command.CommandHelper
import net.superricky.tpaplusplus.config.Config
import net.superricky.tpaplusplus.config.command.CommandDistanceSpec
import net.superricky.tpaplusplus.config.command.CommandNameSpec
Expand Down Expand Up @@ -35,13 +36,11 @@ object ToggleCommand : BuildableCommand, AsyncCommand {
)

private fun switchToggle(context: Context): Int {
val source = context.source
val (result, sender) = CommandHelper.checkSenderReceiver(context, CommandHelper::checkSender)
if (result != CommandResult.NORMAL) return result.status
sender!!
TpaPlusPlus.launch {
val source = context.source
val sender = source.player
if (sender == null) {
source.sendError(Text.translatable("command.toggle.error.sender.not_exist"))
return@launch
}
val blocked = DatabaseManager.playerSwitchBlock(sender.uuid)
if (blocked) {
source.sendFeedback({ Text.translatable("command.toggle.success.on") }, false)
Expand All @@ -53,13 +52,11 @@ object ToggleCommand : BuildableCommand, AsyncCommand {
}

private fun switchToggle(context: Context, blocked: Boolean): Int {
val source = context.source
val (result, sender) = CommandHelper.checkSenderReceiver(context, CommandHelper::checkSender)
if (result != CommandResult.NORMAL) return result.status
sender!!
TpaPlusPlus.launch {
val source = context.source
val sender = source.player
if (sender == null) {
source.sendError(Text.translatable("command.toggle.error.sender.not_exist"))
return@launch
}
if (blocked) {
sender.toggleOn()
source.sendFeedback({ Text.translatable("command.toggle.success.on") }, false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package net.superricky.tpaplusplus.command.commands

import net.minecraft.command.argument.EntityArgumentType
import net.minecraft.server.command.CommandManager.argument
import net.minecraft.server.command.CommandManager.literal
import net.superricky.tpaplusplus.async.AsyncCommandData
import net.superricky.tpaplusplus.async.AsyncCommandHelper
import net.superricky.tpaplusplus.command.AsyncCommand
import net.superricky.tpaplusplus.command.BuildableCommand
import net.superricky.tpaplusplus.command.CommandHelper.checkSenderReceiver
import net.superricky.tpaplusplus.config.Config
import net.superricky.tpaplusplus.config.command.CommandDelaySpec
import net.superricky.tpaplusplus.config.command.CommandDistanceSpec
import net.superricky.tpaplusplus.config.command.CommandNameSpec
import net.superricky.tpaplusplus.utility.LiteralNode
import net.superricky.tpaplusplus.request.Request
import net.superricky.tpaplusplus.utility.*

object TpaCommand : BuildableCommand, AsyncCommand {
override fun build(): LiteralNode =
literal(Config.getConfig()[CommandNameSpec.tpaCommand])
.then(
argument("player", EntityArgumentType.player())
.executes { tpaPlayer(it) }
)
.build()

override fun checkWindupDistance(asyncCommandData: AsyncCommandData): Boolean =
Expand All @@ -20,4 +30,45 @@ object TpaCommand : BuildableCommand, AsyncCommand {
::getSenderDistance,
Config.getConfig()[CommandDistanceSpec.tpaDistance]
)

private fun asyncCommandCallback(result: AsyncCommandResult, request: Request) {
require(request.receiver != null) { "Receiver cannot be null" }
when (result) {
AsyncCommandResult.AFTER_DELAY -> {
request.sender.sendMessage("command.tpa.request.sender", request.receiver)
request.receiver.sendMessage("command.tpa.request.receiver", request.sender)
}

AsyncCommandResult.TIMEOUT -> {
request.sender.sendMessage("command.tpa.timeout.sender", request.receiver)
request.receiver.sendMessage("command.tpa.timeout.receiver", request.sender)
}

AsyncCommandResult.BE_CANCELED -> {
}

AsyncCommandResult.OUT_OF_DISTANCE -> {
request.sender.sendMessage("command.windup.error.out_distance", request.receiver)
request.receiver.sendMessage("command.tpa.request.cancel", request.sender)
}

else -> {}
}
}

private fun tpaPlayer(context: Context): Int {
val source = context.source
val (result, sender, target) = checkSenderReceiver(context)
if (result != CommandResult.NORMAL) return result.status
sender!!
target!!
val asyncCommandData = AsyncCommandData(
Request(sender, target, CommandType.TPA, false),
LevelBoundVec3(sender.getDimension(), sender.pos),
Config.getConfig()[CommandDelaySpec.tpaDelay],
::asyncCommandCallback
)
AsyncCommandHelper.schedule(asyncCommandData)
return CommandResult.NORMAL.status
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import net.superricky.tpaplusplus.TpaPlusPlus
import net.superricky.tpaplusplus.async.AsyncCommandData
import net.superricky.tpaplusplus.command.AsyncCommand
import net.superricky.tpaplusplus.command.BuildableCommand
import net.superricky.tpaplusplus.command.CommandHelper.checkSenderReceiver
import net.superricky.tpaplusplus.config.CommonSpec
import net.superricky.tpaplusplus.config.Config
import net.superricky.tpaplusplus.config.command.CommandDistanceSpec
Expand All @@ -34,20 +35,10 @@ object UnblockCommand : BuildableCommand, AsyncCommand {

private fun unBlockPlayer(context: Context): Int {
val source = context.source
val sender = source.player
val target = EntityArgumentType.getPlayer(context, "player")
if (sender == null) {
source.sendError(Text.translatable("command.error.sender.not_exist"))
return CommandResult.SENDER_NOT_EXIST.status
}
if (target == null) {
source.sendError(Text.translatable("command.error.target.not_exist"))
return CommandResult.TARGET_NOT_EXIST.status
}
if (sender == target) {
source.sendError(Text.translatable("command.unblock.error.self"))
return CommandResult.SELF_CHECK_ERROR.status
}
val (result, sender, target) = checkSenderReceiver(context)
if (result != CommandResult.NORMAL) return result.status
sender!!
target!!
TpaPlusPlus.launch {
if (DatabaseManager.deleteBlockedPlayer(sender.uuid, target.uuid)) {
source.sendFeedback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ object RequestHelper {

fun teleport(request: Request) {
val sender = request.sender
val receiver = request.receiver
val receiver = request.receiver!!

if (request.hereRequest) {
receiver.teleport(sender.serverWorld, sender.x, sender.y, sender.z, sender.yaw, sender.pitch)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ package net.superricky.tpaplusplus.utility
enum class AsyncCommandResult {
BE_CANCELED,
OUT_OF_DISTANCE,
TIMEOUT
TIMEOUT,
AFTER_DELAY
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package net.superricky.tpaplusplus.utility
enum class CommandResult(val status: Int) {
NORMAL(1),
SENDER_NOT_EXIST(-1),
TARGET_NOT_EXIST(-2),
RECEIVER_NOT_EXIST(-2),
SELF_CHECK_ERROR(-3)
}
31 changes: 31 additions & 0 deletions src/main/kotlin/net/superricky/tpaplusplus/utility/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import net.minecraft.text.Style
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.superricky.tpaplusplus.TpaPlusPlus
import net.superricky.tpaplusplus.config.AdvancedSpec
import net.superricky.tpaplusplus.config.Config
import net.superricky.tpaplusplus.database.DatabaseManager

fun String.literal(): MutableText = Text.literal(this)
Expand All @@ -26,3 +28,32 @@ fun PlayerEntity.toggleOff() = TpaPlusPlus.launch {

fun PlayerEntity.getColoredName(color: Style): MutableText? = this.name.literalString?.literal()?.setStyle(color)
fun PlayerEntity.getDimension(): ServerDimension = this.world.registryKey
fun PlayerEntity.sendMessage(
translateKey: String,
player: PlayerEntity,
outStyle: Style = TextColorPallet.primary,
inStyle: Style = TextColorPallet.secondary
) {
this.sendMessage(
Text.translatable(
translateKey,
player.getColoredName(inStyle)
).setStyle(outStyle)
)
}

@Suppress("MagicNumber")
fun Long.translateSecondToTick(): Long =
if (Config.getConfig()[AdvancedSpec.unblockingTickLoop]) {
this * Config.getConfig()[AdvancedSpec.asyncLoopRate]
} else {
this * 20
}

@Suppress("MagicNumber")
fun Double.translateTickToSecond(): Double =
if (Config.getConfig()[AdvancedSpec.unblockingTickLoop]) {
this / Config.getConfig()[AdvancedSpec.asyncLoopRate].toDouble()
} else {
this / 20.0
}
Loading

0 comments on commit abf6b16

Please sign in to comment.