diff options
Diffstat (limited to 'src/main/kotlin/util/mc')
-rw-r--r-- | src/main/kotlin/util/mc/InventoryUtil.kt | 28 | ||||
-rw-r--r-- | src/main/kotlin/util/mc/ItemUtil.kt | 20 | ||||
-rw-r--r-- | src/main/kotlin/util/mc/NbtItemData.kt | 22 | ||||
-rw-r--r-- | src/main/kotlin/util/mc/SkullItemData.kt | 88 |
4 files changed, 158 insertions, 0 deletions
diff --git a/src/main/kotlin/util/mc/InventoryUtil.kt b/src/main/kotlin/util/mc/InventoryUtil.kt new file mode 100644 index 0000000..74f7b9f --- /dev/null +++ b/src/main/kotlin/util/mc/InventoryUtil.kt @@ -0,0 +1,28 @@ +package moe.nea.firmament.util.mc + +import java.util.Spliterator +import java.util.Spliterators +import net.minecraft.inventory.Inventory +import net.minecraft.item.ItemStack + +val Inventory.indices get() = 0 until size() +val Inventory.iterableView + get() = object : Iterable<ItemStack> { + override fun spliterator(): Spliterator<ItemStack> { + return Spliterators.spliterator(iterator(), size().toLong(), 0) + } + + override fun iterator(): Iterator<ItemStack> { + return object : Iterator<ItemStack> { + var i = 0 + override fun hasNext(): Boolean { + return i < size() + } + + override fun next(): ItemStack { + if (!hasNext()) throw NoSuchElementException() + return getStack(i++) + } + } + } + } diff --git a/src/main/kotlin/util/mc/ItemUtil.kt b/src/main/kotlin/util/mc/ItemUtil.kt new file mode 100644 index 0000000..13519cf --- /dev/null +++ b/src/main/kotlin/util/mc/ItemUtil.kt @@ -0,0 +1,20 @@ +package moe.nea.firmament.util.mc + +import net.minecraft.item.ItemStack +import net.minecraft.text.Text + +fun ItemStack.appendLore(args: List<Text>) { + if (args.isEmpty()) return + modifyLore { + val loreList = loreAccordingToNbt.toMutableList() + for (arg in args) { + loreList.add(arg) + } + loreList + } +} + +fun ItemStack.modifyLore(update: (List<Text>) -> List<Text>) { + val loreList = loreAccordingToNbt + loreAccordingToNbt = update(loreList) +} diff --git a/src/main/kotlin/util/mc/NbtItemData.kt b/src/main/kotlin/util/mc/NbtItemData.kt new file mode 100644 index 0000000..e8a908f --- /dev/null +++ b/src/main/kotlin/util/mc/NbtItemData.kt @@ -0,0 +1,22 @@ +package moe.nea.firmament.util.mc + +import net.minecraft.component.DataComponentTypes +import net.minecraft.component.type.LoreComponent +import net.minecraft.item.ItemStack +import net.minecraft.text.Text + +var ItemStack.loreAccordingToNbt + get() = get(DataComponentTypes.LORE)?.lines ?: listOf() + set(value) { + set(DataComponentTypes.LORE, LoreComponent(value)) + } + +var ItemStack.displayNameAccordingToNbt: Text + get() = get(DataComponentTypes.CUSTOM_NAME) ?: get(DataComponentTypes.ITEM_NAME) ?: item.name + set(value) { + set(DataComponentTypes.CUSTOM_NAME, value) + } + +fun ItemStack.setCustomName(text: Text) { + set(DataComponentTypes.CUSTOM_NAME, text) +} diff --git a/src/main/kotlin/util/mc/SkullItemData.kt b/src/main/kotlin/util/mc/SkullItemData.kt new file mode 100644 index 0000000..0405b65 --- /dev/null +++ b/src/main/kotlin/util/mc/SkullItemData.kt @@ -0,0 +1,88 @@ +@file:UseSerializers(DashlessUUIDSerializer::class, InstantAsLongSerializer::class) + +package moe.nea.firmament.util.mc + +import com.mojang.authlib.GameProfile +import com.mojang.authlib.minecraft.MinecraftProfileTexture +import com.mojang.authlib.properties.Property +import java.util.UUID +import kotlinx.datetime.Clock +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers +import kotlinx.serialization.encodeToString +import net.minecraft.component.DataComponentTypes +import net.minecraft.component.type.ProfileComponent +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import moe.nea.firmament.Firmament +import moe.nea.firmament.util.Base64Util.padToValidBase64 +import moe.nea.firmament.util.assertTrueOr +import moe.nea.firmament.util.json.DashlessUUIDSerializer +import moe.nea.firmament.util.json.InstantAsLongSerializer + +@Serializable +data class MinecraftProfileTextureKt( + val url: String, + val metadata: Map<String, String> = mapOf(), +) + +@Serializable +data class MinecraftTexturesPayloadKt( + val textures: Map<MinecraftProfileTexture.Type, MinecraftProfileTextureKt> = mapOf(), + val profileId: UUID? = null, + val profileName: String? = null, + val isPublic: Boolean = true, + val timestamp: Instant = Clock.System.now(), +) + +fun GameProfile.setTextures(textures: MinecraftTexturesPayloadKt) { + val json = Firmament.json.encodeToString(textures) + val encoded = java.util.Base64.getEncoder().encodeToString(json.encodeToByteArray()) + properties.put(propertyTextures, Property(propertyTextures, encoded)) +} + +private val propertyTextures = "textures" + +fun ItemStack.setEncodedSkullOwner(uuid: UUID, encodedData: String) { + assert(this.item == Items.PLAYER_HEAD) + val gameProfile = GameProfile(uuid, "LameGuy123") + gameProfile.properties.put(propertyTextures, Property(propertyTextures, encodedData.padToValidBase64())) + this.set(DataComponentTypes.PROFILE, ProfileComponent(gameProfile)) +} + +val zeroUUID = UUID.fromString("d3cb85e2-3075-48a1-b213-a9bfb62360c1") +fun createSkullItem(uuid: UUID, url: String) = ItemStack(Items.PLAYER_HEAD) + .also { it.setSkullOwner(uuid, url) } + +fun ItemStack.setSkullOwner(uuid: UUID, url: String) { + assert(this.item == Items.PLAYER_HEAD) + val gameProfile = GameProfile(uuid, "nea89") + gameProfile.setTextures( + MinecraftTexturesPayloadKt( + textures = mapOf(MinecraftProfileTexture.Type.SKIN to MinecraftProfileTextureKt(url)), + profileId = uuid, + profileName = "nea89", + ) + ) + this.set(DataComponentTypes.PROFILE, ProfileComponent(gameProfile)) +} + + +fun decodeProfileTextureProperty(property: Property): MinecraftTexturesPayloadKt? { + assertTrueOr(property.name == propertyTextures) { return null } + return try { + var encodedF: String = property.value + while (encodedF.length % 4 != 0 && encodedF.last() == '=') { + encodedF = encodedF.substring(0, encodedF.length - 1) + } + val json = java.util.Base64.getDecoder().decode(encodedF).decodeToString() + Firmament.json.decodeFromString<MinecraftTexturesPayloadKt>(json) + } catch (e: Exception) { + // Malformed profile data + if (Firmament.DEBUG) + e.printStackTrace() + null + } +} + |