aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt12
-rw-r--r--src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/features/misc/HideArmor.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java2
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt90
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/compat/ArrayNormalization.kt6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/compat/GuiScreenUtils.kt59
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/compat/Pattern.java4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/compat/Pattterns.java15
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/compat/SkyhanniBaseScreen.kt10
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/compat/World.kt63
13 files changed, 244 insertions, 28 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt b/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt
index db6ca3c30..817defc5f 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt
+++ b/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt
@@ -28,6 +28,8 @@ import at.hannibal2.skyhanni.mixins.transformers.gui.AccessorGuiContainer
import at.hannibal2.skyhanni.utils.GuiRenderUtils
import at.hannibal2.skyhanni.utils.KeyboardManager
import at.hannibal2.skyhanni.utils.LorenzUtils.round
+import at.hannibal2.skyhanni.utils.compat.GuiScreenUtils
+import at.hannibal2.skyhanni.utils.compat.SkyhanniBaseScreen
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiScreen
import net.minecraft.client.gui.ScaledResolution
@@ -41,7 +43,7 @@ class GuiPositionEditor(
private val positions: List<Position>,
private val border: Int,
private val oldScreen: GuiContainer? = null,
-) : GuiScreen() {
+) : SkyhanniBaseScreen() {
private var grabbedX = 0
private var grabbedY = 0
@@ -147,15 +149,15 @@ class GuiPositionEditor(
return hoveredPos
}
- private fun getScaledHeight() = ScaledResolution(Minecraft.getMinecraft()).scaledHeight
- private fun getScaledWidth() = ScaledResolution(Minecraft.getMinecraft()).scaledWidth
+ private fun getScaledHeight() = GuiScreenUtils.scaledWindowHeight
+ private fun getScaledWidth() = GuiScreenUtils.scaledWindowHeight
@Throws(IOException::class)
override fun mouseClicked(originalX: Int, priginalY: Int, mouseButton: Int) {
super.mouseClicked(originalX, priginalY, mouseButton)
- val mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth
- val mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1
+ val mouseX = GuiScreenUtils.mouseX
+ val mouseY = GuiScreenUtils.mouseY
for (i in positions.indices.reversed()) {
val position = positions[i]
val elementWidth = position.getDummySize().x
diff --git a/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt
index f5566e278..c895b1058 100644
--- a/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt
+++ b/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt
@@ -13,7 +13,7 @@ import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.fml.common.eventhandler.Event
import net.minecraftforge.fml.common.eventhandler.IEventListener
-@Deprecated("Use SkyHanniEvent instead", ReplaceWith(""))
+@Deprecated("Use SkyHanniEvent instead")
abstract class LorenzEvent : Event() {
private val eventName by lazy {
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/HideArmor.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/HideArmor.kt
index 112b59213..32365458f 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/misc/HideArmor.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/HideArmor.kt
@@ -10,11 +10,11 @@ import at.hannibal2.skyhanni.utils.EntityUtils.getArmorInventory
import at.hannibal2.skyhanni.utils.EntityUtils.hasPotionEffect
import at.hannibal2.skyhanni.utils.EntityUtils.isNPC
import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.compat.Effects
import net.minecraft.client.entity.EntityPlayerSP
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
-import net.minecraft.potion.Potion
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@SkyHanniModule
@@ -26,7 +26,7 @@ object HideArmor {
private fun shouldHideArmor(entity: EntityLivingBase): Boolean {
if (!LorenzUtils.inSkyBlock) return false
if (entity !is EntityPlayer) return false
- if (entity.hasPotionEffect(Potion.invisibility)) return false
+ if (entity.hasPotionEffect(Effects.invisibility)) return false
if (entity.isNPC()) return false
return when (config.mode) {
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java
index 3e6d049ca..1aa8c1daf 100644
--- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinFontRenderer.java
@@ -79,7 +79,7 @@ public abstract class MixinFontRenderer {
return ModifyVisualWords.INSTANCE.modifyText(text);
}
- @ModifyVariable(method = "getStringWidth", at = @At("HEAD"), argsOnly = true)
+ @ModifyVariable(method = "getStringWidth(Ljava/lang/String;)I", at = @At("HEAD"), argsOnly = true)
private String getStringWidth(String text) {
return ModifyVisualWords.INSTANCE.modifyText(text);
}
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java
index acec9ffac..0c58469cd 100644
--- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiContainer.java
@@ -71,6 +71,6 @@ public abstract class MixinGuiContainer extends GuiScreen {
)
public void drawScreen_after(int mouseX, int mouseY, float partialTicks, CallbackInfo ci) {
skyHanni$hook.onDrawScreenAfter(mouseX, mouseY, ci);
- ToolTipData.INSTANCE.setLastSlot(theSlot);
+ ToolTipData.INSTANCE.setLastSlot(this.theSlot);
}
}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt
index d0a3c199e..be61fc81c 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt
@@ -13,6 +13,7 @@ import at.hannibal2.skyhanni.utils.chat.Text.hover
import at.hannibal2.skyhanni.utils.chat.Text.onClick
import at.hannibal2.skyhanni.utils.chat.Text.prefix
import at.hannibal2.skyhanni.utils.chat.Text.url
+import at.hannibal2.skyhanni.utils.compat.getFormattedTextCompat
import net.minecraft.client.Minecraft
import net.minecraft.util.ChatComponentText
import net.minecraft.util.ChatStyle
@@ -82,7 +83,7 @@ object ChatUtils {
}
fun chat(message: IChatComponent): Boolean {
- val formattedMessage = message.formattedText
+ val formattedMessage = message.getFormattedTextCompat()
log.log(formattedMessage)
val minecraft = Minecraft.getMinecraft()
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt
index 430310709..d123fa991 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/EntityUtils.kt
@@ -11,9 +11,15 @@ import at.hannibal2.skyhanni.utils.LocationUtils.distanceToIgnoreY
import at.hannibal2.skyhanni.utils.LorenzUtils.baseMaxHealth
import at.hannibal2.skyhanni.utils.LorenzUtils.derpy
import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import at.hannibal2.skyhanni.utils.compat.getArmorOrFullInventory
+import at.hannibal2.skyhanni.utils.compat.getLoadedPlayers
+import at.hannibal2.skyhanni.utils.compat.getNameAsString
+import at.hannibal2.skyhanni.utils.compat.isOnMainThread
+import at.hannibal2.skyhanni.utils.compat.normalizeAsArray
import net.minecraft.block.state.IBlockState
import net.minecraft.client.Minecraft
import net.minecraft.client.entity.EntityOtherPlayerMP
+import net.minecraft.client.multiplayer.WorldClient
import net.minecraft.client.resources.DefaultPlayerSkin
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase
@@ -26,8 +32,11 @@ import net.minecraft.potion.Potion
import net.minecraft.scoreboard.ScorePlayerTeam
import net.minecraft.util.AxisAlignedBB
import net.minecraftforge.client.event.RenderLivingEvent
+
+//#if FORGE
import net.minecraftforge.fml.common.eventhandler.Event
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+//#endif
@SkyHanniModule
object EntityUtils {
@@ -44,7 +53,7 @@ object EntityUtils {
fun getPlayerEntities(): MutableList<EntityOtherPlayerMP> {
val list = mutableListOf<EntityOtherPlayerMP>()
- for (entity in Minecraft.getMinecraft().theWorld.playerEntities) {
+ for (entity in Minecraft.getMinecraft().theWorld?.getLoadedPlayers() ?: emptyList()) {
if (!entity.isNPC() && entity is EntityOtherPlayerMP) {
list.add(entity)
}
@@ -56,7 +65,7 @@ object EntityUtils {
contains: String,
radius: Double = 3.0,
): List<EntityArmorStand> = getArmorStandsInRadius(getLorenzVec().add(y = 3), radius).filter {
- it.name.contains(contains)
+ it.getNameAsString().contains(contains)
}
fun EntityLivingBase.getNameTagWith(
@@ -76,7 +85,7 @@ object EntityUtils {
): List<EntityArmorStand> {
val center = getLorenzVec().add(y = y)
return getArmorStandsInRadius(center, inaccuracy).filter {
- val result = it.name.contains(contains)
+ val result = it.getNameAsString().contains(contains)
if (debugWrongEntity && !result) {
LorenzUtils.consoleLog("wrong entity in aabb: '" + it.name + "'")
}
@@ -139,31 +148,57 @@ object EntityUtils {
fun EntityLivingBase.isAtFullHealth() = baseMaxHealth == health.toInt()
fun EntityArmorStand.hasSkullTexture(skin: String): Boolean {
- if (inventory == null) return false
+ val inventory = this.getArmorOrFullInventory() ?: return false
return inventory.any { it != null && it.getSkullTexture() == skin }
}
fun EntityPlayer.isNPC() = !isRealPlayer()
- fun EntityLivingBase.hasPotionEffect(potion: Potion) = getActivePotionEffect(potion) != null
+ fun EntityLivingBase.hasPotionEffect(
+ potion:
+ //#if MC <1.21
+ Potion,
+ //#else
+ //$$ net.minecraft.registry.entry.RegistryEntry<net.minecraft.entity.effect.StatusEffect>
+ //#endif
+ ) = getActivePotionEffect(potion) != null
fun EntityLivingBase.getArmorInventory(): Array<ItemStack?>? =
- if (this is EntityPlayer) inventory.armorInventory else null
+ if (this is EntityPlayer) inventory.armorInventory.normalizeAsArray() else null
fun EntityEnderman.getBlockInHand(): IBlockState? = heldBlockState
inline fun <reified R : Entity> getEntities(): Sequence<R> = getAllEntities().filterIsInstance<R>()
- fun getAllEntities(): Sequence<Entity> = Minecraft.getMinecraft()?.theWorld?.loadedEntityList?.let {
- if (Minecraft.getMinecraft().isCallingFromMinecraftThread) it else it.toMutableList()
+ private fun WorldClient.getAllEntities(): Iterable<Entity> =
+//#if MC < 1.14
+ loadedEntityList
+//#else
+//$$ entitiesForRendering()
+//#endif
+
+ fun getAllEntities(): Sequence<Entity> = Minecraft.getMinecraft().theWorld?.getAllEntities()?.let {
+ if (Minecraft.getMinecraft()
+ .isOnMainThread()
+ ) it else it.toMutableList() // TODO: while i am here, i want to point out that copying the entity list does not constitute proper synchronization, but *does* make crashes because of it rarer.
}?.asSequence()?.filterNotNull() ?: emptySequence()
fun Entity.canBeSeen(radius: Double = 150.0) = getLorenzVec().add(y = 0.5).canBeSeen(radius)
fun getEntityByID(entityId: Int) = Minecraft.getMinecraft()?.thePlayer?.entityWorld?.getEntityByID(entityId)
+//#if FORGE
+
@SubscribeEvent
- fun onEntityRenderPre(event: RenderLivingEvent.Pre<*>) {
+ fun onEntityRenderPre(
+ event:
+ //#if MC < 1.14
+ RenderLivingEvent.Pre<*>,
+ //#else
+ //$$ RenderLivingEvent.Pre<*, *>
+ //#endif
+
+ ) {
val shEvent = SkyHanniRenderEntityEvent.Pre(event.entity, event.renderer, event.x, event.y, event.z)
if (shEvent.postAndCatch()) {
event.cancel()
@@ -171,12 +206,24 @@ object EntityUtils {
}
@SubscribeEvent
- fun onEntityRenderPost(event: RenderLivingEvent.Post<*>) {
+ fun onEntityRenderPost(
+ event:
+ //#if MC < 11400
+ RenderLivingEvent.Post<*>,
+ //#else
+ //$$ RenderLivingEvent.Post<*, *>
+ //#endif
+
+ ) {
SkyHanniRenderEntityEvent.Post(event.entity, event.renderer, event.x, event.y, event.z).postAndCatch()
}
+//#if MC < 11400
@SubscribeEvent
- fun onEntityRenderSpecialsPre(event: RenderLivingEvent.Specials.Pre<*>) {
+ fun onEntityRenderSpecialsPre(
+ event:
+ RenderLivingEvent.Specials.Pre<*>,
+ ) {
val shEvent = SkyHanniRenderEntityEvent.Specials.Pre(event.entity, event.renderer, event.x, event.y, event.z)
if (shEvent.postAndCatch()) {
event.cancel()
@@ -184,38 +231,47 @@ object EntityUtils {
}
@SubscribeEvent
- fun onEntityRenderSpecialsPost(event: RenderLivingEvent.Specials.Post<*>) {
+ fun onEntityRenderSpecialsPost(
+ event:
+ RenderLivingEvent.Specials.Post<*>,
+ ) {
SkyHanniRenderEntityEvent.Specials.Post(event.entity, event.renderer, event.x, event.y, event.z).postAndCatch()
}
+//#endif
+
+//#endif
fun EntityLivingBase.isCorrupted() = baseMaxHealth == health.toInt().derpy() * 3 || isRunicAndCorrupt()
fun EntityLivingBase.isRunic() = baseMaxHealth == health.toInt().derpy() * 4 || isRunicAndCorrupt()
fun EntityLivingBase.isRunicAndCorrupt() = baseMaxHealth == health.toInt().derpy() * 3 * 4
- fun Entity.cleanName() = this.name.removeColor()
+ fun Entity.cleanName() = this.getNameAsString().removeColor()
/**
* @return a fake player with the same skin as the real player
*/
fun getFakePlayer(): EntityOtherPlayerMP {
val mc = Minecraft.getMinecraft()
+ val player = mc.thePlayer!!
return object : EntityOtherPlayerMP(
mc.theWorld,
- mc.thePlayer.gameProfile
+ player.gameProfile,
) {
override fun getLocationSkin() =
- mc.thePlayer.locationSkin ?: DefaultPlayerSkin.getDefaultSkin(mc.thePlayer.uniqueID)
+ player.getLocationSkin() ?: DefaultPlayerSkin.getDefaultSkin(player.uniqueID)
override fun getTeam() = object : ScorePlayerTeam(null, null) {
override fun getNameTagVisibility() = EnumVisible.NEVER
}
- override fun isWearing(part: EnumPlayerModelParts?) =
- mc.thePlayer.isWearing(part) && part != EnumPlayerModelParts.CAPE
+ override fun isWearing(part: EnumPlayerModelParts): Boolean =
+ player.isWearing(part) && part != EnumPlayerModelParts.CAPE
}
}
}
+//#if FORGE
private fun Event.cancel() {
isCanceled = true
}
+//#endif
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/compat/ArrayNormalization.kt b/src/main/java/at/hannibal2/skyhanni/utils/compat/ArrayNormalization.kt
new file mode 100644
index 000000000..2dde4bdc5
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/compat/ArrayNormalization.kt
@@ -0,0 +1,6 @@
+package at.hannibal2.skyhanni.utils.compat
+
+
+inline fun <reified T> List<T>.normalizeAsArray() = this.toTypedArray()
+fun <T> Array<T>.normalizeAsArray() = this
+
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/compat/GuiScreenUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/compat/GuiScreenUtils.kt
new file mode 100644
index 000000000..0cec5aeb2
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/compat/GuiScreenUtils.kt
@@ -0,0 +1,59 @@
+package at.hannibal2.skyhanni.utils.compat
+
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.ScaledResolution
+import org.lwjgl.input.Mouse
+
+object GuiScreenUtils {
+ private val mc get() = Minecraft.getMinecraft()
+ val scaledWindowHeight
+ get() =
+//#if MC < 1.16
+ ScaledResolution(mc).scaledHeight
+//#else
+//$$ mc.window.guiScaledHeight
+//#endif
+
+ val scaledWindowWidth
+ get() =
+//#if MC < 1.16
+ ScaledResolution(mc).scaledWidth
+//#else
+//$$ mc.window.guiScaledWidth
+//#endif
+
+ val displayWidth
+ get() =
+//#if MC < 1.16
+ mc.displayWidth
+//#else
+//$$ mc.window.width
+//#endif
+
+
+ val displayHeight
+ get() =
+//#if MC < 1.16
+ mc.displayHeight
+//#else
+//$$ mc.window.height
+//#endif
+
+ val globalMouseX get() = Mouse.getX()
+ val globalMouseY get() = Mouse.getY()
+
+ val mouseX
+ get() = globalMouseX * scaledWindowWidth / displayWidth
+ val mouseY: Int
+ get() {
+ val height = this.scaledWindowHeight
+ //TODO: in later versions the height - factor is removed, i think
+ val y = globalMouseY * height / displayHeight
+//#if MC < 1.16
+ return height - y - 1
+//#else
+//$$ return y
+//#endif
+ }
+
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/compat/Pattern.java b/src/main/java/at/hannibal2/skyhanni/utils/compat/Pattern.java
new file mode 100644
index 000000000..f1e3a5f78
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/compat/Pattern.java
@@ -0,0 +1,4 @@
+package at.hannibal2.skyhanni.utils.compat;
+
+public @interface Pattern {
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/compat/Pattterns.java b/src/main/java/at/hannibal2/skyhanni/utils/compat/Pattterns.java
new file mode 100644
index 000000000..c8f6389a1
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/compat/Pattterns.java
@@ -0,0 +1,15 @@
+package at.hannibal2.skyhanni.utils.compat;
+
+import net.minecraft.client.Minecraft;
+
+public class Pattterns {
+
+ @Pattern
+ private static boolean isOnMainThread(Minecraft mc) {
+ //#if MC>=11400
+ //$$ return mc.isOnThread();
+ //#else
+ return mc.isCallingFromMinecraftThread();
+ //#endif
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/compat/SkyhanniBaseScreen.kt b/src/main/java/at/hannibal2/skyhanni/utils/compat/SkyhanniBaseScreen.kt
new file mode 100644
index 000000000..e9b8233ea
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/compat/SkyhanniBaseScreen.kt
@@ -0,0 +1,10 @@
+package at.hannibal2.skyhanni.utils.compat
+
+import net.minecraft.client.gui.GuiScreen
+
+abstract class SkyhanniBaseScreen : GuiScreen(
+ //#if MC > 1.12
+ //$$ net.minecraft.network.chat.TextComponent.EMPTY
+ //#endif
+) {
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/compat/World.kt b/src/main/java/at/hannibal2/skyhanni/utils/compat/World.kt
new file mode 100644
index 000000000..7916eb4e5
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/compat/World.kt
@@ -0,0 +1,63 @@
+package at.hannibal2.skyhanni.utils.compat
+
+import net.minecraft.client.Minecraft
+import net.minecraft.client.multiplayer.WorldClient
+import net.minecraft.entity.Entity
+import net.minecraft.entity.item.EntityArmorStand
+import net.minecraft.entity.player.EntityPlayer
+import net.minecraft.potion.Potion
+import net.minecraft.util.IChatComponent
+
+fun WorldClient.getLoadedPlayers(): List<EntityPlayer> =
+//#if MC < 1.14
+ this.playerEntities
+//#else
+//$$ this.players()
+//#endif
+
+
+fun Entity.getNameAsString(): String =
+ this.name
+//#if MC >= 1.14
+//$$ .getString()
+//#endif
+
+fun EntityArmorStand.getArmorOrFullInventory() =
+//#if MC < 1.12
+ this.inventory
+//#else
+//$$ this.getArmorInventoryList()
+//#endif
+
+fun Minecraft.isOnMainThread() =
+//#if MC < 1.14
+ this.isCallingFromMinecraftThread
+//#else
+//$$ this.isSameThread
+//#endif
+
+fun IChatComponent.getFormattedTextCompat() =
+//#if MC < 1.16
+ this.formattedText
+//#else
+//$$ run {
+//$$ val sb = StringBuilder()
+//$$ for (component in iterator()) {
+//$$ sb.append(component.style.formattingCode)
+//$$ sb.append(component.unformattedComponentText)
+//$$ sb.append("§r")
+//$$ }
+//$$ sb.toString()
+//$$ }
+//#endif
+
+object Effects {
+ val invisibility =
+ //#if MC <1.12
+ Potion.invisibility
+ //#else
+ //$$ net.minecraft.init.PotionTypes.INVISIBILITY
+ //#endif
+}
+
+