Forge recipes and coin items

This commit is contained in:
nea
2023-05-30 22:47:56 +02:00
parent 3139306088
commit 88cb9468b4
10 changed files with 193 additions and 24 deletions

View File

@@ -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.client.registry.display.DisplayCategory
import me.shedaniel.rei.api.common.category.CategoryIdentifier import me.shedaniel.rei.api.common.category.CategoryIdentifier
import me.shedaniel.rei.api.common.util.EntryStacks 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.block.Blocks
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.rei.SBItemEntryDefinition import moe.nea.firmament.rei.SBItemEntryDefinition
import moe.nea.firmament.rei.plus
class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() { class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() {
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier 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 getTitle(): Text = Text.literal("Forge Recipes")
override fun getDisplayHeight(): Int { override fun getDisplayHeight(): Int {
return super.getDisplayHeight() return 104
} }
override fun getIcon(): Renderer = EntryStacks.of(Blocks.ANVIL) override fun getIcon(): Renderer = EntryStacks.of(Blocks.ANVIL)
override fun setupDisplay(display: SBForgeRecipe, bounds: Rectangle): List<Widget> { override fun setupDisplay(display: SBForgeRecipe, bounds: Rectangle): List<Widget> {
return buildList { return buildList {
// TODO: proper gui for this (possibly inspired by the old circular gui)
add(Widgets.createRecipeBase(bounds)) add(Widgets.createRecipeBase(bounds))
val resultSlot = Point(bounds.centerX, bounds.centerY + 5) add(Widgets.createResultSlotBackground(Point(bounds.minX + 124, bounds.minY + 46)))
add(Widgets.createResultSlotBackground(resultSlot)) val arrow = Widgets.createArrow(Point(bounds.minX + 90, bounds.minY + 54 - 18 / 2))
val ingredientsCenter = Point(bounds.centerX, bounds.centerY - 20) 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 val count = display.neuRecipe.inputs.size
display.neuRecipe.inputs.forEachIndexed { idx, ingredient -> if (count == 1) {
add( add(
Widgets.createSlot( Widgets.createSlot(Point(ingredientsCenter.x, ingredientsCenter.y)).markInput()
Point(ingredientsCenter.x + 12 - count * 24 / 2 + idx * 24, ingredientsCenter.y) .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.inputs.single()))
).markInput().entry(SBItemEntryDefinition.getEntry(ingredient))
) )
} 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( add(
Widgets.createSlot(resultSlot).markOutput().disableBackground() Widgets.createSlot(Point(bounds.minX + 124, bounds.minY + 46)).markOutput().disableBackground()
.entry(SBItemEntryDefinition.getEntry(display.neuRecipe.outputStack)) .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.outputStack))
) )
} }

View File

@@ -33,6 +33,7 @@ import net.minecraft.registry.tag.TagKey
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry 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.ItemCache.asItemStack
import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
@@ -43,15 +44,17 @@ data class SBItemStack(
val skyblockId: SkyblockId, val skyblockId: SkyblockId,
val neuItem: NEUItem?, val neuItem: NEUItem?,
val stackSize: Int, 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> { object SBItemEntryDefinition : EntryDefinition<SBItemStack> {
override fun equals(o1: SBItemStack, o2: SBItemStack, context: ComparisonContext): Boolean { override fun equals(o1: SBItemStack, o2: SBItemStack, context: ComparisonContext): Boolean {
if (!context.isFuzzy) { return o1.skyblockId == o2.skyblockId && o1.stackSize == o2.stackSize
if (o1.stackSize != o2.stackSize)
return false
}
return o1.skyblockId == o2.skyblockId
} }
override fun cheatsAs(entry: EntryStack<SBItemStack>?, value: SBItemStack): ItemStack { override fun cheatsAs(entry: EntryStack<SBItemStack>?, value: SBItemStack): ItemStack {

View 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,
)

View File

@@ -18,29 +18,38 @@
package moe.nea.firmament.repo package moe.nea.firmament.repo
import com.mojang.authlib.GameProfile
import com.mojang.authlib.minecraft.MinecraftProfileTexture
import com.mojang.serialization.Dynamic import com.mojang.serialization.Dynamic
import io.github.cottonmc.cotton.gui.client.CottonHud import io.github.cottonmc.cotton.gui.client.CottonHud
import io.github.moulberry.repo.IReloadable import io.github.moulberry.repo.IReloadable
import io.github.moulberry.repo.NEURepository import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.NEUItem
import java.text.NumberFormat
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.minecraft.SharedConstants import net.minecraft.SharedConstants
import net.minecraft.block.entity.SkullBlockEntity
import net.minecraft.client.resource.language.I18n import net.minecraft.client.resource.language.I18n
import net.minecraft.datafixer.Schemas import net.minecraft.datafixer.Schemas
import net.minecraft.datafixer.TypeReferences import net.minecraft.datafixer.TypeReferences
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.Items import net.minecraft.item.Items
import net.minecraft.nbt.NbtCompound import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtElement
import net.minecraft.nbt.NbtHelper
import net.minecraft.nbt.NbtOps import net.minecraft.nbt.NbtOps
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.rei.SBItemStack
import moe.nea.firmament.util.LegacyTagParser import moe.nea.firmament.util.LegacyTagParser
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.appendLore 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 import moe.nea.firmament.util.skyblockId
object ItemCache : IReloadable { object ItemCache : IReloadable {
@@ -73,7 +82,7 @@ object ItemCache : IReloadable {
fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack { fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack {
return ItemStack(Items.PAINTING).apply { 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))) 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 { fun NEUItem?.asItemStack(idHint: SkyblockId? = null): ItemStack {
if (this == null) return brokenItemStack(null, idHint) if (this == null) return brokenItemStack(null, idHint)
var s = cache[this.skyblockItemId] var s = cache[this.skyblockItemId]
@@ -139,4 +143,47 @@ object ItemCache : IReloadable {
CottonHud.remove(RepoManager.progressBar) 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)
} }

View File

@@ -56,6 +56,7 @@ value class SkyblockId(val neuItem: String) {
} }
companion object { companion object {
val COINS: SkyblockId = SkyblockId("SKYBLOCK_COIN")
private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex() private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex()
val NULL: SkyblockId = SkyblockId("null") val NULL: SkyblockId = SkyblockId("null")
} }

View 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))
}

View File

@@ -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("-", ""))
}
}

View File

@@ -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())
}
}

View 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())
}

View File

@@ -35,5 +35,6 @@
"firmament.config.fishing-warning.highlight-wake-chain": "Highlight fishing particles", "firmament.config.fishing-warning.highlight-wake-chain": "Highlight fishing particles",
"firmament.key.slotlocking": "Lock Slot / Slot Binding", "firmament.key.slotlocking": "Lock Slot / Slot Binding",
"firmament.key.category": "Firmament", "firmament.key.category": "Firmament",
"firmament.protectitem": "Firmament protected your item: " "firmament.protectitem": "Firmament protected your item: ",
"firmament.recipe.forge.time": "Forging Time: %s"
} }