diff options
| author | Lorenz <ESs95s3P5z8Pheb> | 2022-07-14 12:06:07 +0200 |
|---|---|---|
| committer | Lorenz <ESs95s3P5z8Pheb> | 2022-07-14 12:06:07 +0200 |
| commit | a5c540d977a3510812cac7fac340fe17e7d10983 (patch) | |
| tree | dbbe5b208e6871378a10868d1206d1d78beeb950 /src/main/java/at/hannibal2/skyhanni/utils | |
| parent | d6c99ed30a2b1cb228b2fdc3d3178cf1f369dc53 (diff) | |
| download | skyhanni-a5c540d977a3510812cac7fac340fe17e7d10983.tar.gz skyhanni-a5c540d977a3510812cac7fac340fe17e7d10983.tar.bz2 skyhanni-a5c540d977a3510812cac7fac340fe17e7d10983.zip | |
renamed mod to SkyHanni
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/utils')
12 files changed, 1182 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt b/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt new file mode 100644 index 000000000..c321cf2d5 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt @@ -0,0 +1,48 @@ +package at.hannibal2.skyhanni.utils + +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import org.apache.http.client.config.RequestConfig +import org.apache.http.client.methods.HttpGet +import org.apache.http.impl.client.HttpClientBuilder +import org.apache.http.impl.client.HttpClients +import org.apache.http.message.BasicHeader +import org.apache.http.util.EntityUtils + + +object APIUtil { + private val parser = JsonParser() + + val builder: HttpClientBuilder = + HttpClients.custom().setUserAgent("SkyHanni") + .setDefaultHeaders( + mutableListOf( + BasicHeader("Pragma", "no-cache"), + BasicHeader("Cache-Control", "no-cache") + ) + ) + .setDefaultRequestConfig( + RequestConfig.custom() + .build() + ) + .useSystemProperties() + + fun getJSONResponse(urlString: String): JsonObject { + val client = builder.build() + try { + client.execute(HttpGet(urlString)).use { response -> + val entity = response.entity + if (entity != null) { + val retSrc = EntityUtils.toString(entity) + return parser.parse(retSrc) as JsonObject + } + } + } catch (ex: Throwable) { + ex.printStackTrace() + LorenzUtils.error("SkyHanni ran into an ${ex::class.simpleName ?: "error"} whilst fetching a resource. See logs for more details.") + } finally { + client.close() + } + return JsonObject() + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/BlockUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/BlockUtils.kt new file mode 100644 index 000000000..368b06daf --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/BlockUtils.kt @@ -0,0 +1,23 @@ +package at.hannibal2.skyhanni.utils + +import net.minecraft.block.Block +import net.minecraft.client.Minecraft +import net.minecraft.tileentity.TileEntitySkull +import net.minecraft.util.BlockPos +import net.minecraftforge.common.util.Constants + +object BlockUtils { + + fun LorenzVec.getBlockAt(): Block = + Minecraft.getMinecraft().theWorld.getBlockState(toBlocPos()).block + + fun LorenzVec.isInLoadedChunk(): Boolean = + Minecraft.getMinecraft().theWorld.chunkProvider.provideChunk(toBlocPos()).isLoaded + + fun getSkinFromSkull(position: BlockPos?): String? { + val entity = Minecraft.getMinecraft().theWorld.getTileEntity(position) as TileEntitySkull + val serializeNBT = entity.serializeNBT() + return serializeNBT.getCompoundTag("Owner").getCompoundTag("Properties") + .getTagList("textures", Constants.NBT.TAG_COMPOUND).getCompoundTagAt(0).getString("Value") + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/GuiRender.kt b/src/main/java/at/hannibal2/skyhanni/utils/GuiRender.kt new file mode 100644 index 000000000..221cbd9a2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/GuiRender.kt @@ -0,0 +1,32 @@ +package at.hannibal2.skyhanni.utils + +import at.hannibal2.skyhanni.config.core.config.Position +import at.hannibal2.skyhanni.utils.LorenzUtils.removeColorCodes +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.ScaledResolution +import net.minecraft.client.renderer.GlStateManager + +object GuiRender { + + fun Position.renderString(string: String) { + val textToRender = "§f$string" + + GlStateManager.pushMatrix() + val resolution = ScaledResolution(Minecraft.getMinecraft()) + + val renderer = Minecraft.getMinecraft().renderManager.fontRenderer + + val offsetX = (200 - renderer.getStringWidth(textToRender.removeColorCodes())) / 2 + + val x = getAbsX(resolution, 200) + offsetX + val y = getAbsY(resolution, 16) + + + + GlStateManager.translate(x + 1.0, y + 1.0, 0.0) + renderer.drawStringWithShadow(textToRender, 0f, 0f, 0) + + + GlStateManager.popMatrix() + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ItemUtil.kt b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtil.kt new file mode 100644 index 000000000..d10adc06c --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtil.kt @@ -0,0 +1,213 @@ +package at.hannibal2.skyhanni.utils + +import net.minecraft.init.Items +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.nbt.NBTTagList +import net.minecraft.nbt.NBTTagString +import net.minecraftforge.common.util.Constants +import java.util.* + +object ItemUtil { + private val PET_PATTERN = "§7\\[Lvl \\d+] (?<color>§[0-9a-fk-or]).+".toRegex() + const val NBT_INTEGER = 3 + private const val NBT_STRING = 8 + private const val NBT_LIST = 9 + private const val NBT_COMPOUND = 10 + + /** + * Returns the display name of a given item + * @author Mojang + * @param item the Item to get the display name of + * @return the display name of the item + */ + @JvmStatic + fun getDisplayName(item: ItemStack): String { + var s = item.item.getItemStackDisplayName(item) + if (item.tagCompound != null && item.tagCompound.hasKey("display", 10)) { + val nbtTagCompound = item.tagCompound.getCompoundTag("display") + if (nbtTagCompound.hasKey("Name", 8)) { + s = nbtTagCompound.getString("Name") + } + } + return s + } + + /** + * Returns the Skyblock Item ID of a given Skyblock item + * + * @author BiscuitDevelopment + * @param item the Skyblock item to check + * @return the Skyblock Item ID of this item or `null` if this isn't a valid Skyblock item + */ + @JvmStatic + fun getSkyBlockItemID(item: ItemStack?): String? { + if (item == null) { + return null + } + val extraAttributes = getExtraAttributes(item) ?: return null + return if (!extraAttributes.hasKey("id", NBT_STRING)) { + null + } else extraAttributes.getString("id") + } + + /** + * Returns the `ExtraAttributes` compound tag from the item's NBT data. + * + * @author BiscuitDevelopment + * @param item the item to get the tag from + * @return the item's `ExtraAttributes` compound tag or `null` if the item doesn't have one + */ + @JvmStatic + fun getExtraAttributes(item: ItemStack?): NBTTagCompound? { + return if (item == null || !item.hasTagCompound()) { + null + } else item.getSubCompound("ExtraAttributes", false) + } + + /** + * Returns the Skyblock Item ID of a given Skyblock Extra Attributes NBT Compound + * + * @author BiscuitDevelopment + * @param extraAttributes the NBT to check + * @return the Skyblock Item ID of this item or `null` if this isn't a valid Skyblock NBT + */ + @JvmStatic + fun getSkyBlockItemID(extraAttributes: NBTTagCompound?): String? { + if (extraAttributes != null) { + val itemId = extraAttributes.getString("id") + if (itemId.isNotEmpty()) { + return itemId + } + } + return null + } + + /** + * Returns a string list containing the nbt lore of an ItemStack, or + * an empty list if this item doesn't have a lore. The returned lore + * list is unmodifiable since it has been converted from an NBTTagList. + * + * @author BiscuitDevelopment + * @param itemStack the ItemStack to get the lore from + * @return the lore of an ItemStack as a string list + */ + @JvmStatic + fun getItemLore(itemStack: ItemStack): List<String> { + if (itemStack.hasTagCompound() && itemStack.tagCompound.hasKey("display", NBT_COMPOUND)) { + val display = itemStack.tagCompound.getCompoundTag("display") + if (display.hasKey("Lore", NBT_LIST)) { + val lore = display.getTagList("Lore", NBT_STRING) + val loreAsList = ArrayList<String>(lore.tagCount()) + for (lineNumber in 0 until lore.tagCount()) { + loreAsList.add(lore.getStringTagAt(lineNumber)) + } + return Collections.unmodifiableList(loreAsList) + } + } + return emptyList() + } + +// @JvmStatic +// fun hasRightClickAbility(itemStack: ItemStack): Boolean { +// for (line in getItemLore(itemStack)) { +// val stripped = line.stripControlCodes() +// if (stripped.startsWith("Item Ability:") && stripped.endsWith("RIGHT CLICK")) return true +// } +// return false +// } + +// /** +// * Returns the rarity of a given Skyblock item +// * Modified +// * @author BiscuitDevelopment +// * @param item the Skyblock item to check +// * @return the rarity of the item if a valid rarity is found, `null` if no rarity is found, `null` if item is `null` +// */ +// fun getRarity(item: ItemStack?): ItemRarity { +// if (item == null || !item.hasTagCompound()) { +// return ItemRarity.NONE +// } +// val display = item.getSubCompound("display", false) +// if (display == null || !display.hasKey("Lore")) { +// return ItemRarity.NONE +// } +// val lore = display.getTagList("Lore", Constants.NBT.TAG_STRING) +// val name = display.getString("Name") +// +// // Determine the item's rarity +// for (i in (lore.tagCount() - 1) downTo 0) { +// val currentLine = lore.getStringTagAt(i) +// val rarityMatcher = RARITY_PATTERN.find(currentLine) +// if (rarityMatcher != null) { +// val rarity = rarityMatcher.groups["rarity"]?.value ?: continue +// ItemRarity.values().find { +// it.rarityName == rarity.stripControlCodes().substringAfter("SHINY ") +// }?.let { +// return it +// } +// } +// } +// val petRarityMatcher = PET_PATTERN.find(name) +// if (petRarityMatcher != null) { +// val color = petRarityMatcher.groupValues.getOrNull(1) ?: return ItemRarity.NONE +// return ItemRarity.byBaseColor(color) ?: ItemRarity.NONE +// } +// +// // If the item doesn't have a valid rarity, return null +// return ItemRarity.NONE +// } + + fun isPet(item: ItemStack?): Boolean { + if (item == null || !item.hasTagCompound()) { + return false + } + val display = item.getSubCompound("display", false) + if (display == null || !display.hasKey("Lore")) { + return false + } + val name = display.getString("Name") + + return PET_PATTERN.matches(name) + } + + fun setSkullTexture(item: ItemStack, texture: String, SkullOwner: String): ItemStack { + val textureTagCompound = NBTTagCompound() + textureTagCompound.setString("Value", texture) + + val textures = NBTTagList() + textures.appendTag(textureTagCompound) + + val properties = NBTTagCompound() + properties.setTag("textures", textures) + + val skullOwner = NBTTagCompound() + skullOwner.setString("Id", SkullOwner) + skullOwner.setTag("Properties", properties) + + val nbtTag = NBTTagCompound() + nbtTag.setTag("SkullOwner", skullOwner) + + item.tagCompound = nbtTag + return item + } + + fun getSkullTexture(item: ItemStack): String? { + if (item.item != Items.skull) return null + val nbt = item.tagCompound + if (!nbt.hasKey("SkullOwner")) return null + return nbt.getCompoundTag("SkullOwner").getCompoundTag("Properties") + .getTagList("textures", Constants.NBT.TAG_COMPOUND).getCompoundTagAt(0).getString("Value") + } + + fun ItemStack.setLore(lines: List<String>): ItemStack { + setTagInfo("display", getSubCompound("display", true).apply { + setTag("Lore", NBTTagList().apply { + for (line in lines) appendTag(NBTTagString(line)) + }) + }) + return this + } + + fun NBTTagList.asStringSet() = (0..tagCount()).mapTo(hashSetOf()) { getStringTagAt(it) } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt new file mode 100644 index 000000000..b077c4121 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/ItemUtils.kt @@ -0,0 +1,72 @@ +package at.hannibal2.skyhanni.utils + +import at.hannibal2.skyhanni.utils.LorenzUtils.matchRegex +import at.hannibal2.skyhanni.utils.LorenzUtils.removeColorCodes +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.inventory.GuiChest +import net.minecraft.item.ItemStack + +object ItemUtils { + + fun ItemStack.cleanName() = this.displayName.removeColorCodes() + + fun getItemsInOpenChest(): List<ItemStack> { + val list = mutableListOf<ItemStack>() + val guiChest = Minecraft.getMinecraft().currentScreen as GuiChest + val inventorySlots = guiChest.inventorySlots.inventorySlots + val skipAt = inventorySlots.size - 9 * 4 + var i = 0 + for (slot in inventorySlots) { + val stack = slot.stack + if (stack != null) { + list.add(stack) + } + i++ + if (i == skipAt) break + } + return list + } + + fun isSack(name: String): Boolean = name.endsWith(" Sack") + + fun ItemStack.getLore() = ItemUtil.getItemLore(this) + + fun isCoOpSoulBound(stack: ItemStack): Boolean = stack.getLore().any { it.contains("Co-op Soulbound") } + + fun isRecombobulated(stack: ItemStack): Boolean = stack.getLore().any { it.contains("§k") } + + fun isPet(name: String): Boolean = name.matchRegex("\\[Lvl (.*)] (.*)") && !listOf( + "Archer", + "Berserk", + "Mage", + "Tank", + "Healer", + "➡", + ).any { name.contains(it) } + + fun maxPetLevel(name: String) = if (name.contains("Golden Dragon")) 200 else 100 + + fun getItemsInInventoryWithSlots(withCursorItem: Boolean = false): Map<ItemStack, Int> { + val map: LinkedHashMap<ItemStack, Int> = LinkedHashMap() + val player = Minecraft.getMinecraft().thePlayer + if (player == null) { + LorenzUtils.warning("getItemsInInventoryWithSlots: player is null!") + return map + } + for (slot in player.openContainer.inventorySlots) { + if (slot.hasStack) { + map[slot.stack] = slot.slotNumber + } + } + + if (withCursorItem) { + if (player.inventory != null) { + if (player.inventory.itemStack != null) { + map[player.inventory.itemStack] = -1 + } + } + } + + return map + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzColor.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzColor.kt new file mode 100644 index 000000000..961ed57ec --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzColor.kt @@ -0,0 +1,27 @@ +package at.hannibal2.skyhanni.utils + +import java.awt.Color + +enum class LorenzColor(private var chatColorCode: Char, private val color: Color) { + BLACK('0', Color(0, 0, 0)), + DARK_BLUE('1', Color(0, 0, 170)), + DARK_GREEN('2', Color(0, 170, 0)), + DARK_AQUA('3', Color(0, 170, 170)), + DARK_RED('4', Color(170, 0, 0)), + DARK_PURPLE('5', Color(170, 0, 170)), + GOLD('6', Color(255, 170, 0)), + GRAY('7', Color(170, 170, 170)), + DARK_GRAY('8', Color(85, 85, 85)), + BLUE('9', Color(85, 85, 255)), + GREEN('a', Color(85, 255, 85)), + AQUA('b', Color(85, 255, 255)), + RED('c', Color(255, 85, 85)), + LIGHT_PURPLE('d', Color(255, 85, 255)), + YELLOW('e', Color(255, 255, 85)), + WHITE('f', Color(255, 255, 255)), + ; + + fun getChatColor(): String = "§$chatColorCode" + + fun toColor(): Color = color +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzDebug.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzDebug.kt new file mode 100644 index 000000000..5212dfc95 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzDebug.kt @@ -0,0 +1,16 @@ +package at.hannibal2.skyhanni.utils + +object LorenzDebug { + + private val logger = LorenzLogger("debug") + + fun log(text: String) { + logger.log(text) + println("debug logger: $text") + } + + fun writeAndLog(text: String) { + LorenzUtils.debug(text) + log(text) + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzLogger.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzLogger.kt new file mode 100644 index 000000000..23ca8df25 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzLogger.kt @@ -0,0 +1,70 @@ +package at.hannibal2.skyhanni.utils + +import at.hannibal2.skyhanni.utils.LorenzUtils.formatCurrentTime +import java.io.File +import java.io.IOException +import java.text.SimpleDateFormat +import java.util.logging.FileHandler +import java.util.logging.Formatter +import java.util.logging.LogRecord +import java.util.logging.Logger + +class LorenzLogger(filePath: String) { + private val format = SimpleDateFormat("HH:mm:ss") + private val fileName = "$PREFIX_PATH$filePath.log" + + companion object { + private var PREFIX_PATH: String + + init { + val format = SimpleDateFormat("yyyy_MM_dd/HH_mm_ss").formatCurrentTime() + PREFIX_PATH = "mods/SkyHanni/logs/$format/" + } + } + + private lateinit var logger: Logger + + private fun getLogger(): Logger { + if (::logger.isInitialized) { + return logger + } + + val initLogger = initLogger() + this.logger = initLogger + return initLogger + } + + private fun initLogger(): Logger { + val logger = Logger.getLogger("" + System.nanoTime()) + try { + createParent(File(fileName)) + val handler = FileHandler(fileName) + handler.encoding ="utf-8" + logger.addHandler(handler) + handler.formatter = object : Formatter() { + override fun format(logRecord: LogRecord): String { + val message = logRecord.message + return format.formatCurrentTime() + " $message\n" + } + } + } catch (e: SecurityException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + return logger + } + + private fun createParent(file: File) { + val parent = file.parentFile + if (parent != null) { + if (!parent.isDirectory) { + parent.mkdirs() + } + } + } + + fun log(text: String?) { + getLogger().info(text) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt new file mode 100644 index 000000000..13afe8ac2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzUtils.kt @@ -0,0 +1,113 @@ +package at.hannibal2.skyhanni.utils + +import at.hannibal2.skyhanni.misc.HypixelData +import net.minecraft.client.Minecraft +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.SharedMonsterAttributes +import net.minecraft.util.ChatComponentText +import org.intellij.lang.annotations.Language +import java.text.DecimalFormat +import java.text.SimpleDateFormat + +object LorenzUtils { + + val isOnHypixel: Boolean + get() = HypixelData.hypixel + + val inSkyblock: Boolean + get() = HypixelData.hypixel && HypixelData.skyblock + + val inDungeons: Boolean + get() = HypixelData.hypixel && HypixelData.skyblock && HypixelData.dungeon + + const val DEBUG_PREFIX = "[Debug] §7" + + fun debug(message: String) { + internalChat(DEBUG_PREFIX + message) + } + + fun warning(message: String) { + internalChat("§cWarning! $message") + } + + fun error(message: String) { + internalChat("§4$message") + } + + fun chat(message: String) { + internalChat(message) + } + + private fun internalChat(message: String) { + val minecraft = Minecraft.getMinecraft() + if (minecraft == null) { + println(message) + return + } + + val thePlayer = minecraft.thePlayer + if (thePlayer == null) { + println(message) + return + } + + thePlayer.addChatMessage(ChatComponentText(message)) + } + + fun String.matchRegex(@Language("RegExp") regex: String): Boolean = regex.toRegex().matches(this) + + fun String.removeColorCodes(): String { + val builder = StringBuilder() + var skipNext = false + for (c in this.toCharArray()) { + if (c == '§') { + skipNext = true + continue + } + if (skipNext) { + skipNext = false + continue + } + builder.append(c) + } + + return builder.toString() + } + + fun SimpleDateFormat.formatCurrentTime(): String = this.format(System.currentTimeMillis()) + + fun stripVanillaMessage(originalMessage: String): String { + var message = originalMessage + + while (message.startsWith("§r")) { + message = message.substring(2) + } + while (message.endsWith("§r")) { + message = message.substring(0, message.length - 2) + } + return message + } + + fun Double.round(decimals: Int): Double { + var multiplier = 1.0 + repeat(decimals) { multiplier *= 10 } + return kotlin.math.round(this * multiplier) / multiplier + } + + fun String.between(start: String, end: String): String = this.split(start, end)[1] + + val EntityLivingBase.baseMaxHealth: Double + get() = this.getEntityAttribute(SharedMonsterAttributes.maxHealth).baseValue + + fun formatPercentage(percentage: Double): String = formatPercentage(percentage, "0.00") + + fun formatPercentage(percentage: Double, format: String?): String = + DecimalFormat(format).format(percentage * 100).replace(',', '.') + "%" + + fun formatInteger(i: Int): String = DecimalFormat("#,##0").format(i.toLong()).replace(',', '.') + + fun formatDouble(d: Double, format: String?): String = + DecimalFormat(format).format(d).replace(',', 'x').replace('.', ',').replace('x', '.') + + fun formatDouble(d: Double): String = formatDouble(d, "#,##0.0") +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt new file mode 100644 index 000000000..bfc5f7228 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt @@ -0,0 +1,61 @@ +package at.hannibal2.skyhanni.utils + +import net.minecraft.entity.Entity +import net.minecraft.util.BlockPos +import net.minecraft.util.Vec3 +import kotlin.math.pow + +data class LorenzVec( + val x: Double, + val y: Double, + val z: Double +) { + constructor(x: Int, y: Int, z: Int) : this(x.toDouble(), y.toDouble(), z.toDouble()) + + fun toBlocPos(): BlockPos = BlockPos(x, y, z) + + fun toVec3(): Vec3 = Vec3(x, y, z) + + fun distance(other: LorenzVec): Double = distanceSq(other).pow(0.5) + + fun distanceSq(x: Double, y: Double, z: Double): Double = distanceSq(LorenzVec(x, y, z)) + + fun distance(x: Double, y: Double, z: Double): Double = distance(LorenzVec(x, y, z)) + + fun distanceSq(other: LorenzVec): Double { + val dx = (other.x - x) + val dy = (other.y - y) + val dz = (other.z - z) + return (dx * dx + dy * dy + dz * dz) + } + + fun add(x: Double, y: Double, z: Double): LorenzVec = LorenzVec(this.x + x, this.y + y, this.z + z) + + fun add(x: Int, y: Int, z: Int): LorenzVec = LorenzVec(this.x + x, this.y + y, this.z + z) + + override fun toString(): String { + return "LorenzVec{" + + "x=" + x + + ", y=" + y + + ", z=" + z + + '}' + } + + fun multiply(d: Double): LorenzVec = LorenzVec(x multiplyZeroSave d, y multiplyZeroSave d, z multiplyZeroSave d) + + fun multiply(d: Int): LorenzVec = + LorenzVec(x multiplyZeroSave d.toDouble(), y multiplyZeroSave d.toDouble(), z multiplyZeroSave d.toDouble()) + + fun add(other: LorenzVec) = LorenzVec(x + other.x, y + other.y, z + other.z) +} + +private infix fun Double.multiplyZeroSave(other: Double): Double { + val result = this * other + return if (result == -0.0) 0.0 else result +} + +fun BlockPos.toLorenzVec(): LorenzVec = LorenzVec(x, y, z) + +fun Entity.getLorenzVec(): LorenzVec = LorenzVec(posX, posY, posZ) + +fun Vec3.toLorenzVec(): LorenzVec = LorenzVec(xCoord, yCoord, zCoord)
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/NumberUtil.kt b/src/main/java/at/hannibal2/skyhanni/utils/NumberUtil.kt new file mode 100644 index 000000000..891826a91 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/NumberUtil.kt @@ -0,0 +1,152 @@ +package at.hannibal2.skyhanni.utils + +import java.text.NumberFormat +import java.util.* +import kotlin.math.pow +import kotlin.math.roundToInt + +object NumberUtil { + @JvmField + val nf: NumberFormat = NumberFormat.getInstance(Locale.US) + private val suffixes = TreeMap<Long, String>().apply { + this[1000L] = "k" + this[1000000L] = "M" + this[1000000000L] = "B" + this[1000000000000L] = "T" + this[1000000000000000L] = "P" + this[1000000000000000000L] = "E" + } + private val romanSymbols = TreeMap( + mapOf( + 1000 to "M", + 900 to "CM", + 500 to "D", + 400 to "CD", + 100 to "C", + 90 to "XC", + 50 to "L", + 40 to "XL", + 10 to "X", + 9 to "IX", + 5 to "V", + 4 to "IV", + 1 to "I", + ) + ) + + /** + * This code was unmodified and taken under CC BY-SA 3.0 license + * @link https://stackoverflow.com/a/30661479 + * @author assylias + */ + @JvmStatic + fun format(value: Number): String { + @Suppress("NAME_SHADOWING") + val value = value.toLong() + //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here + if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1) + if (value < 0) return "-" + format(-value) + if (value < 1000) return value.toString() //deal with easy case + val (divideBy, suffix) = suffixes.floorEntry(value) + val truncated = value / (divideBy / 10) //the number part of the output times 10 + val hasDecimal = truncated < 100 && truncated / 10.0 != (truncated / 10).toDouble() + return if (hasDecimal) (truncated / 10.0).toString() + suffix else (truncated / 10).toString() + suffix + } + + @JvmStatic + fun unformat(value: String): Long { + val suffix = value.filter { !it.isDigit() }.lowercase() + val num = value.filter { it.isDigit() }.toLong() + return num * (suffixes.entries.find { it.value.lowercase() == suffix }?.key ?: 1) + } + + /** + * This code was unmodified and taken under CC BY-SA 3.0 license + * @link https://stackoverflow.com/a/22186845 + * @author jpdymond + */ + fun Double.roundToPrecision(precision: Int): Double { + val scale = 10.0.pow(precision).toInt() + return (this * scale).roundToInt().toDouble() / scale + } + + /** + * This code was unmodified and taken under CC BY-SA 3.0 license + * @link https://stackoverflow.com/a/22186845 + * @author jpdymond + */ + fun Float.roundToPrecision(precision: Int): Float { + val scale = 10.0.pow(precision).toInt() + return (this * scale).roundToInt().toFloat() / scale + } + + fun Number.addSuffix(): String { + val long = this.toLong() + if (long in 11..13) return "${this}th" + return when (long % 10) { + 1L -> "${this}st" + 2L -> "${this}nd" + 3L -> "${this}rd" + else -> "${this}th" + } + } + + /** + * This code was converted to Kotlin and taken under CC BY-SA 3.0 license + * @link https://stackoverflow.com/a/9073310 + */ + fun String.romanToDecimal(): Int { + var decimal = 0 + var lastNumber = 0 + val romanNumeral = this.uppercase() + for (x in romanNumeral.length - 1 downTo 0) { + when (romanNumeral[x]) { + 'M' -> { + decimal = processDecimal(1000, lastNumber, decimal) + lastNumber = 1000 + } + 'D' -> { + decimal = processDecimal(500, lastNumber, decimal) + lastNumber = 500 + } + 'C' -> { + decimal = processDecimal(100, lastNumber, decimal) + lastNumber = 100 + } + 'L' -> { + decimal = processDecimal(50, lastNumber, decimal) + lastNumber = 50 + } + 'X' -> { + decimal = processDecimal(10, lastNumber, decimal) + lastNumber = 10 + } + 'V' -> { + decimal = processDecimal(5, lastNumber, decimal) + lastNumber = 5 + } + 'I' -> { + decimal = processDecimal(1, lastNumber, decimal) + lastNumber = 1 + } + } + } + return decimal + } + + fun Int.toRoman(): String { + if (this <= 0) error("$this must be positive!") + val l = romanSymbols.floorKey(this) + return if (this == l) { + romanSymbols[this]!! + } else romanSymbols[l] + (this - l).toRoman() + } + + private fun processDecimal(decimal: Int, lastNumber: Int, lastDecimal: Int): Int { + return if (lastNumber > decimal) { |
