Forge recipes and coin items
This commit is contained in:
@@ -27,10 +27,14 @@ import me.shedaniel.rei.api.client.gui.widgets.Widgets
|
||||
import me.shedaniel.rei.api.client.registry.display.DisplayCategory
|
||||
import me.shedaniel.rei.api.common.category.CategoryIdentifier
|
||||
import me.shedaniel.rei.api.common.util.EntryStacks
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import net.minecraft.block.Blocks
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.rei.SBItemEntryDefinition
|
||||
import moe.nea.firmament.rei.plus
|
||||
|
||||
class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() {
|
||||
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier
|
||||
@@ -41,27 +45,39 @@ class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() {
|
||||
|
||||
override fun getTitle(): Text = Text.literal("Forge Recipes")
|
||||
override fun getDisplayHeight(): Int {
|
||||
return super.getDisplayHeight()
|
||||
return 104
|
||||
}
|
||||
|
||||
override fun getIcon(): Renderer = EntryStacks.of(Blocks.ANVIL)
|
||||
override fun setupDisplay(display: SBForgeRecipe, bounds: Rectangle): List<Widget> {
|
||||
return buildList {
|
||||
// TODO: proper gui for this (possibly inspired by the old circular gui)
|
||||
add(Widgets.createRecipeBase(bounds))
|
||||
val resultSlot = Point(bounds.centerX, bounds.centerY + 5)
|
||||
add(Widgets.createResultSlotBackground(resultSlot))
|
||||
val ingredientsCenter = Point(bounds.centerX, bounds.centerY - 20)
|
||||
add(Widgets.createResultSlotBackground(Point(bounds.minX + 124, bounds.minY + 46)))
|
||||
val arrow = Widgets.createArrow(Point(bounds.minX + 90, bounds.minY + 54 - 18 / 2))
|
||||
add(arrow)
|
||||
add(Widgets.createTooltip(arrow.bounds, Text.translatable("firmament.recipe.forge.time", display.neuRecipe.duration.seconds)))
|
||||
val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
|
||||
val count = display.neuRecipe.inputs.size
|
||||
display.neuRecipe.inputs.forEachIndexed { idx, ingredient ->
|
||||
if (count == 1) {
|
||||
add(
|
||||
Widgets.createSlot(
|
||||
Point(ingredientsCenter.x + 12 - count * 24 / 2 + idx * 24, ingredientsCenter.y)
|
||||
).markInput().entry(SBItemEntryDefinition.getEntry(ingredient))
|
||||
Widgets.createSlot(Point(ingredientsCenter.x, ingredientsCenter.y)).markInput()
|
||||
.entry(SBItemEntryDefinition.getEntry(display.neuRecipe.inputs.single()))
|
||||
)
|
||||
} else {
|
||||
display.neuRecipe.inputs.forEachIndexed { idx, ingredient ->
|
||||
val rad = Math.PI * 2 * idx / count
|
||||
add(
|
||||
Widgets.createSlot(
|
||||
Point(
|
||||
cos(rad) * 30,
|
||||
sin(rad) * 30,
|
||||
) + ingredientsCenter
|
||||
).markInput().entry(SBItemEntryDefinition.getEntry(ingredient))
|
||||
)
|
||||
}
|
||||
}
|
||||
add(
|
||||
Widgets.createSlot(resultSlot).markOutput().disableBackground()
|
||||
Widgets.createSlot(Point(bounds.minX + 124, bounds.minY + 46)).markOutput().disableBackground()
|
||||
.entry(SBItemEntryDefinition.getEntry(display.neuRecipe.outputStack))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry
|
||||
import moe.nea.firmament.repo.ItemCache
|
||||
import moe.nea.firmament.repo.ItemCache.asItemStack
|
||||
import moe.nea.firmament.repo.RepoManager
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
@@ -43,15 +44,17 @@ data class SBItemStack(
|
||||
val skyblockId: SkyblockId,
|
||||
val neuItem: NEUItem?,
|
||||
val stackSize: Int,
|
||||
)
|
||||
) {
|
||||
fun asItemStack(): ItemStack? {
|
||||
if (skyblockId == SkyblockId.COINS)
|
||||
return ItemCache.coinItem(stackSize)
|
||||
return neuItem.asItemStack(idHint = skyblockId).copyWithCount(stackSize)
|
||||
}
|
||||
}
|
||||
|
||||
object SBItemEntryDefinition : EntryDefinition<SBItemStack> {
|
||||
override fun equals(o1: SBItemStack, o2: SBItemStack, context: ComparisonContext): Boolean {
|
||||
if (!context.isFuzzy) {
|
||||
if (o1.stackSize != o2.stackSize)
|
||||
return false
|
||||
}
|
||||
return o1.skyblockId == o2.skyblockId
|
||||
return o1.skyblockId == o2.skyblockId && o1.stackSize == o2.stackSize
|
||||
}
|
||||
|
||||
override fun cheatsAs(entry: EntryStack<SBItemStack>?, value: SBItemStack): ItemStack {
|
||||
|
||||
8
src/main/kotlin/moe/nea/firmament/rei/math.kt
Normal file
8
src/main/kotlin/moe/nea/firmament/rei/math.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package moe.nea.firmament.rei
|
||||
|
||||
import me.shedaniel.math.Point
|
||||
|
||||
operator fun Point.plus(other: Point): Point = Point(
|
||||
this.x + other.x,
|
||||
this.y + other.y,
|
||||
)
|
||||
@@ -18,29 +18,38 @@
|
||||
|
||||
package moe.nea.firmament.repo
|
||||
|
||||
import com.mojang.authlib.GameProfile
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture
|
||||
import com.mojang.serialization.Dynamic
|
||||
import io.github.cottonmc.cotton.gui.client.CottonHud
|
||||
import io.github.moulberry.repo.IReloadable
|
||||
import io.github.moulberry.repo.NEURepository
|
||||
import io.github.moulberry.repo.data.NEUItem
|
||||
import java.text.NumberFormat
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import net.minecraft.SharedConstants
|
||||
import net.minecraft.block.entity.SkullBlockEntity
|
||||
import net.minecraft.client.resource.language.I18n
|
||||
import net.minecraft.datafixer.Schemas
|
||||
import net.minecraft.datafixer.TypeReferences
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.Items
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtElement
|
||||
import net.minecraft.nbt.NbtHelper
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.rei.SBItemStack
|
||||
import moe.nea.firmament.util.LegacyTagParser
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.appendLore
|
||||
import moe.nea.firmament.util.item.MinecraftProfileTextureKt
|
||||
import moe.nea.firmament.util.item.MinecraftTexturesPayloadKt
|
||||
import moe.nea.firmament.util.item.setTextures
|
||||
import moe.nea.firmament.util.skyblockId
|
||||
|
||||
object ItemCache : IReloadable {
|
||||
@@ -73,7 +82,7 @@ object ItemCache : IReloadable {
|
||||
|
||||
fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack {
|
||||
return ItemStack(Items.PAINTING).apply {
|
||||
setCustomName(Text.literal(neuItem?.displayName ?: idHint?.toString() ?: "null"))
|
||||
setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null"))
|
||||
appendLore(listOf(Text.translatable("firmament.repo.brokenitem", neuItem?.skyblockItemId ?: idHint)))
|
||||
}
|
||||
}
|
||||
@@ -94,11 +103,6 @@ object ItemCache : IReloadable {
|
||||
}
|
||||
}
|
||||
|
||||
fun SBItemStack.asItemStack(): ItemStack {
|
||||
return this.neuItem.asItemStack(idHint = this.skyblockId)
|
||||
.let { if (this.stackSize != 1) it.copyWithCount(this.stackSize) else it }
|
||||
}
|
||||
|
||||
fun NEUItem?.asItemStack(idHint: SkyblockId? = null): ItemStack {
|
||||
if (this == null) return brokenItemStack(null, idHint)
|
||||
var s = cache[this.skyblockItemId]
|
||||
@@ -139,4 +143,47 @@ object ItemCache : IReloadable {
|
||||
CottonHud.remove(RepoManager.progressBar)
|
||||
}
|
||||
}
|
||||
|
||||
fun coinItem(coinAmount: Int): ItemStack {
|
||||
var uuid = UUID.fromString("2070f6cb-f5db-367a-acd0-64d39a7e5d1b")
|
||||
var texture =
|
||||
"http://textures.minecraft.net/texture/538071721cc5b4cd406ce431a13f86083a8973e1064d2f8897869930ee6e5237"
|
||||
if (coinAmount >= 100000) {
|
||||
uuid = UUID.fromString("94fa2455-2881-31fe-bb4e-e3e24d58dbe3")
|
||||
texture =
|
||||
"http://textures.minecraft.net/texture/c9b77999fed3a2758bfeaf0793e52283817bea64044bf43ef29433f954bb52f6"
|
||||
}
|
||||
if (coinAmount >= 10000000) {
|
||||
uuid = UUID.fromString("0af8df1f-098c-3b72-ac6b-65d65fd0b668")
|
||||
texture =
|
||||
"http://textures.minecraft.net/texture/7b951fed6a7b2cbc2036916dec7a46c4a56481564d14f945b6ebc03382766d3b"
|
||||
}
|
||||
val itemStack = ItemStack(Items.PLAYER_HEAD)
|
||||
itemStack.setCustomName(Text.literal("§r§6" + NumberFormat.getInstance().format(coinAmount) + " Coins"))
|
||||
val nbt: NbtCompound = itemStack.orCreateNbt
|
||||
nbt[SkullBlockEntity.SKULL_OWNER_KEY] = NbtHelper.writeGameProfile(
|
||||
NbtCompound(),
|
||||
GameProfile(uuid, "CoolGuy123").also {
|
||||
it.setTextures(
|
||||
MinecraftTexturesPayloadKt(
|
||||
mapOf(
|
||||
MinecraftProfileTexture.Type.SKIN to MinecraftProfileTextureKt(texture),
|
||||
),
|
||||
uuid,
|
||||
"CoolGuy123"
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
return itemStack
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
operator fun NbtCompound.set(key: String, value: String) {
|
||||
putString(key, value)
|
||||
}
|
||||
|
||||
operator fun NbtCompound.set(key: String, value: NbtElement) {
|
||||
put(key, value)
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ value class SkyblockId(val neuItem: String) {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val COINS: SkyblockId = SkyblockId("SKYBLOCK_COIN")
|
||||
private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex()
|
||||
val NULL: SkyblockId = SkyblockId("null")
|
||||
}
|
||||
|
||||
39
src/main/kotlin/moe/nea/firmament/util/item/SkullItemData.kt
Normal file
39
src/main/kotlin/moe/nea/firmament/util/item/SkullItemData.kt
Normal file
@@ -0,0 +1,39 @@
|
||||
@file:UseSerializers(DashlessUUIDSerializer::class, InstantAsLongSerializer::class)
|
||||
|
||||
package moe.nea.firmament.util.item
|
||||
|
||||
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.client.texture.PlayerSkinProvider
|
||||
import moe.nea.firmament.Firmament
|
||||
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>,
|
||||
val profileId: UUID,
|
||||
val profileName: String,
|
||||
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(PlayerSkinProvider.TEXTURES, Property(PlayerSkinProvider.TEXTURES, encoded))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package moe.nea.firmament.util.json
|
||||
|
||||
import java.util.UUID
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import moe.nea.firmament.util.parseDashlessUUID
|
||||
|
||||
object DashlessUUIDSerializer : KSerializer<UUID> {
|
||||
override val descriptor: SerialDescriptor =
|
||||
PrimitiveSerialDescriptor("DashlessUUIDSerializer", PrimitiveKind.STRING)
|
||||
|
||||
override fun deserialize(decoder: Decoder): UUID {
|
||||
return parseDashlessUUID(decoder.decodeString())
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: UUID) {
|
||||
encoder.encodeString(value.toString().replace("-", ""))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package moe.nea.firmament.util.json
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
object InstantAsLongSerializer : KSerializer<Instant> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("InstantAsLongSerializer", PrimitiveKind.LONG)
|
||||
override fun deserialize(decoder: Decoder): Instant {
|
||||
return Instant.fromEpochMilliseconds(decoder.decodeLong())
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Instant) {
|
||||
encoder.encodeLong(value.toEpochMilliseconds())
|
||||
}
|
||||
}
|
||||
10
src/main/kotlin/moe/nea/firmament/util/uuid.kt
Normal file
10
src/main/kotlin/moe/nea/firmament/util/uuid.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package moe.nea.firmament.util
|
||||
|
||||
import java.math.BigInteger
|
||||
import java.util.UUID
|
||||
|
||||
fun parseDashlessUUID(dashlessUuid: String): UUID {
|
||||
val most = BigInteger(dashlessUuid.substring(0, 16), 16)
|
||||
val least = BigInteger(dashlessUuid.substring(16, 32), 16)
|
||||
return UUID(most.toLong(), least.toLong())
|
||||
}
|
||||
@@ -35,5 +35,6 @@
|
||||
"firmament.config.fishing-warning.highlight-wake-chain": "Highlight fishing particles",
|
||||
"firmament.key.slotlocking": "Lock Slot / Slot Binding",
|
||||
"firmament.key.category": "Firmament",
|
||||
"firmament.protectitem": "Firmament protected your item: "
|
||||
"firmament.protectitem": "Firmament protected your item: ",
|
||||
"firmament.recipe.forge.time": "Forging Time: %s"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user