/*
* Copyright (C) 2023 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
* NotEnoughUpdates is free software: you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* NotEnoughUpdates is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with NotEnoughUpdates. If not, see .
*/
package io.github.moulberry.notenoughupdates.commands.dev
import com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg
import com.mojang.brigadier.builder.ArgumentBuilder
import io.github.moulberry.notenoughupdates.NotEnoughUpdates
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe
import io.github.moulberry.notenoughupdates.events.RegisterBrigadierCommandEvent
import io.github.moulberry.notenoughupdates.util.Utils
import io.github.moulberry.notenoughupdates.util.brigadier.*
import net.minecraft.block.state.IBlockState
import net.minecraft.client.Minecraft
import net.minecraft.client.entity.AbstractClientPlayer
import net.minecraft.command.ICommandSender
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLiving
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.item.EntityArmorStand
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntitySkull
import net.minecraft.util.EnumChatFormatting
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@NEUAutoSubscribe
class PackDevCommand {
fun > U.npcListCommand(
name: String,
singleCommand: String,
multipleCommand: String,
clazz: Class,
provider: () -> List
) {
fun getEntities(distance: Double): List {
val distanceSquared = distance * distance
val thePlayer = Minecraft.getMinecraft().thePlayer
return provider()
.asSequence()
.filterIsInstance(clazz)
.filter { it != thePlayer }
.filter { it.getDistanceSqToEntity(thePlayer) < distanceSquared }
.toList()
}
thenLiteral(singleCommand) {
thenArgumentExecute("distance", doubleArg(0.0)) { dist ->
val dist = this[dist]
val entity = getEntities(dist).minByOrNull { it.getDistanceSqToEntity(Minecraft.getMinecraft().thePlayer) }
if (entity == null) {
reply("No $name found within $dist blocks")
return@thenArgumentExecute
}
Utils.copyToClipboard(StringBuilder().also { it.appendEntityData(entity) }.toString().trim())
reply("Copied data to clipboard")
}.withHelp("Find the nearest $name and copy data about them to your clipboard")
}
thenLiteral(multipleCommand) {
thenArgumentExecute("distance", doubleArg(0.0)) { dist ->
val dist = this[dist]
val entity = getEntities(dist)
val sb = StringBuilder()
reply("Found ${entity.size} ${name}s")
if (entity.isNotEmpty()) {
entity.forEach {
sb.appendEntityData(it)
}
Utils.copyToClipboard(sb.toString().trim())
reply("Copied data to clipboard")
}
}.withHelp("Find all $name within range and copy data about them to your clipboard")
}
}
fun StringBuilder.appendEntityData(entity: EntityLivingBase) {
if (entity is EntityPlayer) {
append("Player UUID: ")
appendLine(entity.uniqueID)
if (entity is AbstractClientPlayer) {
append("Entity Texture Id: ")
appendLine(entity.locationSkin.resourcePath?.replace("skins/", ""))
}
}
append("Custom Name Tag: ")
appendLine(entity.customNameTag ?: "null")
append("Mob: ")
appendLine(entity.name)
append("Entity Id: ")
appendLine(entity.entityId)
appendItemData("Item", entity.heldItem)
for ((slot, name) in listOf("Boots", "Leggings", "Chestplate", "Helmet").withIndex()) {
val armorPiece = entity.getCurrentArmor(slot)
appendItemData(name, armorPiece)
}
appendLine()
appendLine()
}
fun StringBuilder.appendItemData(name: String, item: ItemStack?) {
append("$name: ")
if (item != null) {
appendLine(item)
append("$name Display Name")
appendLine(item.displayName)
append("$name Tag Compound: ")
val compound = item.tagCompound
if (compound == null) {
appendLine("null")
} else {
appendLine(compound)
append("$name Tag Compound Extra Attributes")
appendLine(compound.getTag("ExtraAttributes"))
}
} else {
appendLine("null")
}
}
@SubscribeEvent
fun onCommands(event: RegisterBrigadierCommandEvent) {
event.command("neupackdev") {
npcListCommand("Player", "getplayer", "getplayers", AbstractClientPlayer::class.java) {
Minecraft.getMinecraft().theWorld.playerEntities
}
npcListCommand("NPC", "getnpc", "getnpcs", AbstractClientPlayer::class.java) {
Minecraft.getMinecraft().theWorld.playerEntities.filter { it.uniqueID?.version() != 4 }
}
npcListCommand("mob", "getmob", "getmobs", EntityLiving::class.java) {
Minecraft.getMinecraft().theWorld.loadedEntityList
}
npcListCommand("armor stand", "getarmorstand", "getarmorstands", EntityArmorStand::class.java) {
Minecraft.getMinecraft().theWorld.loadedEntityList
}
thenLiteralExecute("block") {
val pos = Minecraft.getMinecraft().thePlayer.rayTrace(4.0, 10f).blockPos
val block: IBlockState = Minecraft.getMinecraft().theWorld.getBlockState(pos)
if (block.block.hasTileEntity(block)) {
val te = Minecraft.getMinecraft().theWorld.getTileEntity(pos)
val s = StringBuilder().also {
it.appendLine("NBT: ${te.tileData}")
if (te is TileEntitySkull && te.playerProfile != null) {
it.appendLine("PlayerProfile:\nId: ")
it.appendLine(te.playerProfile.id)
it.append("Name: ")
it.appendLine(te.playerProfile.name)
it.append("Textures: ")
it.appendLine(te.playerProfile.properties.get("textures")?.firstOrNull()?.value)
}
}.toString().trim()
Utils.copyToClipboard(s)
reply("Copied data to clipboard")
return@thenLiteralExecute
}
reply("No tile entity found at your cursor")
}.withHelp("Find the tile entity you're looking at and copy data about it to your clipboard")
thenExecute {
NotEnoughUpdates.INSTANCE.packDevEnabled = !NotEnoughUpdates.INSTANCE.packDevEnabled
if (NotEnoughUpdates.INSTANCE.packDevEnabled) {
reply("${EnumChatFormatting.GREEN}Enabled pack developer mode.")
} else {
reply("${EnumChatFormatting.RED}Disabled pack developer mode.")
}
}
}.withHelp("Toggle pack developer mode")
}
}