diff --git a/src/main/kotlin/com/lambda/client/capeapi/AbstractUUIDManager.kt b/src/main/kotlin/com/lambda/client/capeapi/AbstractUUIDManager.kt index 5ea46e3ee..825feb079 100644 --- a/src/main/kotlin/com/lambda/client/capeapi/AbstractUUIDManager.kt +++ b/src/main/kotlin/com/lambda/client/capeapi/AbstractUUIDManager.kt @@ -74,7 +74,7 @@ abstract class AbstractUUIDManager( val response = if (isUUID) requestProfileFromUUID(nameOrUUID) else requestProfileFromName(nameOrUUID) return if (response.isNullOrBlank()) { - logger.error("Response is null or blank, internet might be down") + // If there is no player with the given username or UUID an HTTP status code 204 (No Content) is sent without any HTTP body. null } else { try { diff --git a/src/main/kotlin/com/lambda/client/module/modules/render/MobOwner.kt b/src/main/kotlin/com/lambda/client/module/modules/render/MobOwner.kt index 65020b141..deb9dbbbd 100644 --- a/src/main/kotlin/com/lambda/client/module/modules/render/MobOwner.kt +++ b/src/main/kotlin/com/lambda/client/module/modules/render/MobOwner.kt @@ -6,11 +6,16 @@ import com.lambda.client.module.Category import com.lambda.client.module.Module import com.lambda.client.util.threads.runSafe import com.lambda.client.util.threads.safeListener +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityLiving import net.minecraft.entity.passive.AbstractHorse import net.minecraft.entity.passive.EntityTameable import net.minecraftforge.fml.common.gameevent.TickEvent +import java.util.* import kotlin.math.pow +private data class EntityData(var originalCustomNameTag: String, var previous: String? = null) + object MobOwner : Module( name = "MobOwner", description = "Displays the owner of tamed mobs", @@ -22,58 +27,77 @@ object MobOwner : Module( private const val invalidText = "Offline or invalid UUID!" + // nullUUIDs caches all UUID's that returned an empty response from the Mojang API, effectively removing the endless + // HTTP requests and subsequent rate-limit. + private val nullUUIDs = mutableSetOf() + + // originalCustomNameTags does two things. It stores an EntityData data class for every tamable entity. + // In EntityData the original customNameTag is stored that someone might have applied to the entity, a stateful + // previous variable holds the last customNameTag to keep track when a new customNameTag is applied by a player. + private val originalCustomNameTags = mutableMapOf() + init { safeListener { - for (entity in world.loadedEntityList) { - /* Non Horse types, such as wolves */ - if (entity is EntityTameable) { - val ownerUUID = entity.ownerId - if (!entity.isTamed || ownerUUID == null) continue - - val ownerName = UUIDManager.getByUUID(ownerUUID)?.name ?: invalidText - entity.alwaysRenderNameTag = true - entity.customNameTag = "Owner: " + ownerName + getHealth(entity) + /* Non Horse types, such as wolves */ + world.loadedEntityList.filterIsInstance().filter { + it.isTamed + }.forEach { entity -> + entity.ownerId?.let { + changeEntityData(it, entity) } + } - if (entity is AbstractHorse) { - val ownerUUID = entity.ownerUniqueId - if (!entity.isTame || ownerUUID == null) continue - - val ownerName = UUIDManager.getByUUID(ownerUUID)?.name ?: invalidText - entity.alwaysRenderNameTag = true - entity.customNameTag = "Owner: " + ownerName + getSpeed(entity) + getJump(entity) + getHealth(entity) + world.loadedEntityList.filterIsInstance().filter { + it.isTame + }.forEach { entity -> + entity.ownerUniqueId?.let { + changeEntityData(it, entity) } } } onDisable { runSafe { - for (entity in world.loadedEntityList) { - if (entity !is AbstractHorse) continue + // Revert customNameTag back to original. + world.loadedEntityList.filterNotNull().forEach { + val entityData = originalCustomNameTags[it.uniqueID] + it.customNameTag = entityData?.originalCustomNameTag ?: it.customNameTag - try { - entity.alwaysRenderNameTag = false - } catch (_: Exception) { - // Ignored - } + it.alwaysRenderNameTag = false } + + originalCustomNameTags.clear() + nullUUIDs.clear() } } } - private fun getSpeed(horse: AbstractHorse): String { - return if (!speed) "" else " S: " + round(43.17 * horse.aiMoveSpeed, 2) + private fun changeEntityData(ownerUUID: UUID, entity: Entity) { + val owner = if (nullUUIDs.contains(ownerUUID)) null else UUIDManager.getByUUID(ownerUUID) + val ownerName = if (owner == null) { + nullUUIDs.add(ownerUUID) + invalidText + } else { + owner.name + } + val entityData = originalCustomNameTags.getOrPut(entity.uniqueID) { EntityData(originalCustomNameTag = entity.customNameTag) } + if (entityData.previous != null && entity.customNameTag != entityData.previous) { + entityData.originalCustomNameTag = entity.customNameTag + } + entity.alwaysRenderNameTag = true + entity.customNameTag = "${if (entityData.originalCustomNameTag != "") "${entityData.originalCustomNameTag} | " else ""}Owner: " + ownerName + getData(entity as EntityLiving) + entityData.previous = entity.customNameTag } - private fun getJump(horse: AbstractHorse): String { - return if (!jump) "" else " J: " + round(-0.1817584952 * horse.horseJumpStrength.pow(3.0) + 3.689713992 * horse.horseJumpStrength.pow(2.0) + 2.128599134 * horse.horseJumpStrength - 0.343930367, 2) - } + private fun getData(entity: EntityLiving): String { + var data = "" + if (entity is AbstractHorse) { + if (speed) data += " S: " + round(43.17 * entity.aiMoveSpeed, 2) + if (jump) data += " J: " + round(-0.1817584952 * entity.horseJumpStrength.pow(3.0) + 3.689713992 * entity.horseJumpStrength.pow(2.0) + 2.128599134 * entity.horseJumpStrength - 0.343930367, 2) + } - private fun getHealth(horse: AbstractHorse): String { - return if (!hp) "" else " HP: " + round(horse.health, 2) - } + if (hp) data += " HP: " + round(entity.health, 2) - private fun getHealth(tameable: EntityTameable): String { - return if (!hp) "" else " HP: " + round(tameable.health, 2) + return data } } \ No newline at end of file