Merge branch 'mc-1.21.3'
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
package moe.nea.firmament.repo
|
||||
|
||||
import io.github.moulberry.repo.IReloadable
|
||||
@@ -6,23 +5,22 @@ import io.github.moulberry.repo.NEURepository
|
||||
import io.github.moulberry.repo.data.NEURecipe
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
|
||||
class BetterRepoRecipeCache(val essenceRecipeProvider: EssenceRecipeProvider) : IReloadable {
|
||||
var usages: Map<SkyblockId, Set<NEURecipe>> = mapOf()
|
||||
var recipes: Map<SkyblockId, Set<NEURecipe>> = mapOf()
|
||||
class BetterRepoRecipeCache(vararg val extraProviders: ExtraRecipeProvider) : IReloadable {
|
||||
var usages: Map<SkyblockId, Set<NEURecipe>> = mapOf()
|
||||
var recipes: Map<SkyblockId, Set<NEURecipe>> = mapOf()
|
||||
|
||||
override fun reload(repository: NEURepository) {
|
||||
val usages = mutableMapOf<SkyblockId, MutableSet<NEURecipe>>()
|
||||
val recipes = mutableMapOf<SkyblockId, MutableSet<NEURecipe>>()
|
||||
val baseRecipes = repository.items.items.values
|
||||
.asSequence()
|
||||
.flatMap { it.recipes }
|
||||
val extraRecipes = essenceRecipeProvider.recipes
|
||||
(baseRecipes + extraRecipes)
|
||||
.forEach { recipe ->
|
||||
recipe.allInputs.forEach { usages.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
|
||||
recipe.allOutputs.forEach { recipes.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
|
||||
}
|
||||
this.usages = usages
|
||||
this.recipes = recipes
|
||||
}
|
||||
override fun reload(repository: NEURepository) {
|
||||
val usages = mutableMapOf<SkyblockId, MutableSet<NEURecipe>>()
|
||||
val recipes = mutableMapOf<SkyblockId, MutableSet<NEURecipe>>()
|
||||
val baseRecipes = repository.items.items.values
|
||||
.asSequence()
|
||||
.flatMap { it.recipes }
|
||||
(baseRecipes + extraProviders.flatMap { it.provideExtraRecipes() })
|
||||
.forEach { recipe ->
|
||||
recipe.allInputs.forEach { usages.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
|
||||
recipe.allOutputs.forEach { recipes.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) }
|
||||
}
|
||||
this.usages = usages
|
||||
this.recipes = recipes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
package moe.nea.firmament.repo
|
||||
|
||||
import io.github.moulberry.repo.IReloadable
|
||||
@@ -7,44 +6,46 @@ import io.github.moulberry.repo.data.NEUIngredient
|
||||
import io.github.moulberry.repo.data.NEURecipe
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
|
||||
class EssenceRecipeProvider : IReloadable {
|
||||
data class EssenceUpgradeRecipe(
|
||||
val itemId: SkyblockId,
|
||||
val starCountAfter: Int,
|
||||
val essenceCost: Int,
|
||||
val essenceType: String, // TODO: replace with proper type
|
||||
val extraItems: List<NEUIngredient>,
|
||||
) : NEURecipe {
|
||||
val essenceIngredient= NEUIngredient.fromString("${essenceType}:$essenceCost")
|
||||
val allUpgradeComponents = listOf(essenceIngredient) + extraItems
|
||||
class EssenceRecipeProvider : IReloadable, ExtraRecipeProvider {
|
||||
data class EssenceUpgradeRecipe(
|
||||
val itemId: SkyblockId,
|
||||
val starCountAfter: Int,
|
||||
val essenceCost: Int,
|
||||
val essenceType: String, // TODO: replace with proper type
|
||||
val extraItems: List<NEUIngredient>,
|
||||
) : NEURecipe {
|
||||
val essenceIngredient = NEUIngredient.fromString("${essenceType}:$essenceCost")
|
||||
val allUpgradeComponents = listOf(essenceIngredient) + extraItems
|
||||
|
||||
override fun getAllInputs(): Collection<NEUIngredient> {
|
||||
return listOf(NEUIngredient.fromString(itemId.neuItem + ":1")) + allUpgradeComponents
|
||||
}
|
||||
override fun getAllInputs(): Collection<NEUIngredient> {
|
||||
return listOf(NEUIngredient.fromString(itemId.neuItem + ":1")) + allUpgradeComponents
|
||||
}
|
||||
|
||||
override fun getAllOutputs(): Collection<NEUIngredient> {
|
||||
return listOf(NEUIngredient.fromString(itemId.neuItem + ":1"))
|
||||
}
|
||||
}
|
||||
override fun getAllOutputs(): Collection<NEUIngredient> {
|
||||
return listOf(NEUIngredient.fromString(itemId.neuItem + ":1"))
|
||||
}
|
||||
}
|
||||
|
||||
var recipes = listOf<EssenceUpgradeRecipe>()
|
||||
private set
|
||||
var recipes = listOf<EssenceUpgradeRecipe>()
|
||||
private set
|
||||
|
||||
override fun reload(repository: NEURepository) {
|
||||
val recipes = mutableListOf<EssenceUpgradeRecipe>()
|
||||
for ((neuId, costs) in repository.constants.essenceCost.costs) {
|
||||
// TODO: add dungeonization costs. this is in repo, but not in the repo parser.
|
||||
for ((starCountAfter, essenceCost) in costs.essenceCosts.entries) {
|
||||
val items = costs.itemCosts[starCountAfter] ?: emptyList()
|
||||
recipes.add(
|
||||
EssenceUpgradeRecipe(
|
||||
SkyblockId(neuId),
|
||||
starCountAfter,
|
||||
essenceCost,
|
||||
"ESSENCE_" + costs.type.uppercase(), // how flimsy
|
||||
items.map { NEUIngredient.fromString(it) }))
|
||||
}
|
||||
}
|
||||
this.recipes = recipes
|
||||
}
|
||||
override fun provideExtraRecipes(): Iterable<NEURecipe> = recipes
|
||||
|
||||
override fun reload(repository: NEURepository) {
|
||||
val recipes = mutableListOf<EssenceUpgradeRecipe>()
|
||||
for ((neuId, costs) in repository.constants.essenceCost.costs) {
|
||||
// TODO: add dungeonization costs. this is in repo, but not in the repo parser.
|
||||
for ((starCountAfter, essenceCost) in costs.essenceCosts.entries) {
|
||||
val items = costs.itemCosts[starCountAfter] ?: emptyList()
|
||||
recipes.add(
|
||||
EssenceUpgradeRecipe(
|
||||
SkyblockId(neuId),
|
||||
starCountAfter,
|
||||
essenceCost,
|
||||
"ESSENCE_" + costs.type.uppercase(), // how flimsy
|
||||
items.map { NEUIngredient.fromString(it) }))
|
||||
}
|
||||
}
|
||||
this.recipes = recipes
|
||||
}
|
||||
}
|
||||
|
||||
7
src/main/kotlin/repo/ExtraRecipeProvider.kt
Normal file
7
src/main/kotlin/repo/ExtraRecipeProvider.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
package moe.nea.firmament.repo
|
||||
|
||||
import io.github.moulberry.repo.data.NEURecipe
|
||||
|
||||
interface ExtraRecipeProvider {
|
||||
fun provideExtraRecipes(): Iterable<NEURecipe>
|
||||
}
|
||||
@@ -24,21 +24,27 @@ import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtElement
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.nbt.NbtString
|
||||
import net.minecraft.text.Style
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.gui.config.HudMeta
|
||||
import moe.nea.firmament.gui.config.HudPosition
|
||||
import moe.nea.firmament.gui.hud.MoulConfigHud
|
||||
import moe.nea.firmament.repo.RepoManager.initialize
|
||||
import moe.nea.firmament.util.LegacyFormattingCode
|
||||
import moe.nea.firmament.util.LegacyTagParser
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.TestUtil
|
||||
import moe.nea.firmament.util.directLiteralStringContent
|
||||
import moe.nea.firmament.util.mc.FirmamentDataComponentTypes
|
||||
import moe.nea.firmament.util.mc.appendLore
|
||||
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||
import moe.nea.firmament.util.mc.modifyLore
|
||||
import moe.nea.firmament.util.mc.setCustomName
|
||||
import moe.nea.firmament.util.mc.setSkullOwner
|
||||
import moe.nea.firmament.util.transformEachRecursively
|
||||
|
||||
object ItemCache : IReloadable {
|
||||
private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap()
|
||||
@@ -94,6 +100,35 @@ object ItemCache : IReloadable {
|
||||
}
|
||||
}
|
||||
|
||||
fun un189Lore(lore: String): Text {
|
||||
val base = Text.literal("")
|
||||
base.setStyle(Style.EMPTY.withItalic(false))
|
||||
var lastColorCode = Style.EMPTY
|
||||
var readOffset = 0
|
||||
while (readOffset < lore.length) {
|
||||
var nextCode = lore.indexOf('§', readOffset)
|
||||
if (nextCode < 0) {
|
||||
nextCode = lore.length
|
||||
}
|
||||
val text = lore.substring(readOffset, nextCode)
|
||||
if (text.isNotEmpty()) {
|
||||
base.append(Text.literal(text).setStyle(lastColorCode))
|
||||
}
|
||||
readOffset = nextCode + 2
|
||||
if (nextCode + 1 < lore.length) {
|
||||
val colorCode = lore[nextCode + 1]
|
||||
val formatting = LegacyFormattingCode.byCode[colorCode.lowercaseChar()] ?: LegacyFormattingCode.RESET
|
||||
val modernFormatting = formatting.modern
|
||||
if (modernFormatting.isColor) {
|
||||
lastColorCode = Style.EMPTY.withColor(modernFormatting)
|
||||
} else {
|
||||
lastColorCode = lastColorCode.withFormatting(modernFormatting)
|
||||
}
|
||||
}
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
private fun NEUItem.asItemStackNow(): ItemStack {
|
||||
try {
|
||||
val oldItemTag = get10809CompoundTag()
|
||||
@@ -101,6 +136,8 @@ object ItemCache : IReloadable {
|
||||
?: return brokenItemStack(this)
|
||||
val itemInstance =
|
||||
ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
|
||||
itemInstance.loreAccordingToNbt = lore.map { un189Lore(it) }
|
||||
itemInstance.displayNameAccordingToNbt = un189Lore(displayName)
|
||||
val extraAttributes = oldItemTag.getCompound("tag").getCompound("ExtraAttributes")
|
||||
if (extraAttributes != null)
|
||||
itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes))
|
||||
@@ -135,12 +172,13 @@ object ItemCache : IReloadable {
|
||||
}
|
||||
|
||||
fun Text.applyLoreReplacements(loreReplacements: Map<String, String>): Text {
|
||||
assert(this.siblings.isEmpty())
|
||||
var string = this.string
|
||||
loreReplacements.forEach { (find, replace) ->
|
||||
string = string.replace("{$find}", replace)
|
||||
return this.transformEachRecursively {
|
||||
var string = it.directLiteralStringContent ?: return@transformEachRecursively it
|
||||
loreReplacements.forEach { (find, replace) ->
|
||||
string = string.replace("{$find}", replace)
|
||||
}
|
||||
Text.literal(string).setStyle(it.style)
|
||||
}
|
||||
return Text.literal(string).styled { this.style }
|
||||
}
|
||||
|
||||
var job: Job? = null
|
||||
|
||||
160
src/main/kotlin/repo/Reforge.kt
Normal file
160
src/main/kotlin/repo/Reforge.kt
Normal file
@@ -0,0 +1,160 @@
|
||||
package moe.nea.firmament.repo
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.builtins.MapSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.serializer
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.util.Identifier
|
||||
import moe.nea.firmament.util.ReforgeId
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.skyblock.ItemType
|
||||
import moe.nea.firmament.util.skyblock.Rarity
|
||||
|
||||
@Serializable
|
||||
data class Reforge(
|
||||
val reforgeName: String,
|
||||
@SerialName("internalName") val reforgeStone: SkyblockId? = null,
|
||||
val nbtModifier: ReforgeId? = null,
|
||||
val requiredRarities: List<Rarity>? = null,
|
||||
val itemTypes: @Serializable(with = ReforgeEligibilityFilter.ItemTypesSerializer::class) List<ReforgeEligibilityFilter>? = null,
|
||||
val allowOn: List<ReforgeEligibilityFilter>? = null,
|
||||
val reforgeCosts: RarityMapped<Double>? = null,
|
||||
val reforgeAbility: RarityMapped<String>? = null,
|
||||
val reforgeStats: RarityMapped<Map<String, Double>>? = null,
|
||||
) {
|
||||
val eligibleItems get() = allowOn ?: itemTypes ?: listOf()
|
||||
|
||||
val statUniverse: Set<String> = Rarity.entries.flatMapTo(mutableSetOf()) {
|
||||
reforgeStats?.get(it)?.keys ?: emptySet()
|
||||
}
|
||||
|
||||
@Serializable(with = ReforgeEligibilityFilter.Serializer::class)
|
||||
sealed interface ReforgeEligibilityFilter {
|
||||
object ItemTypesSerializer : KSerializer<List<ReforgeEligibilityFilter>> {
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = JsonElement.serializer().descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): List<ReforgeEligibilityFilter> {
|
||||
decoder as JsonDecoder
|
||||
val jsonElement = decoder.decodeJsonElement()
|
||||
if (jsonElement is JsonPrimitive && jsonElement.isString) {
|
||||
return jsonElement.content.split("/").map { AllowsItemType(ItemType.ofName(it)) }
|
||||
}
|
||||
if (jsonElement is JsonArray) {
|
||||
return decoder.json.decodeFromJsonElement(serializer<List<ReforgeEligibilityFilter>>(), jsonElement)
|
||||
}
|
||||
jsonElement as JsonObject
|
||||
val filters = mutableListOf<ReforgeEligibilityFilter>()
|
||||
jsonElement["internalName"]?.let {
|
||||
decoder.json.decodeFromJsonElement(serializer<List<SkyblockId>>(), it).forEach {
|
||||
filters.add(AllowsInternalName(it))
|
||||
}
|
||||
}
|
||||
jsonElement["itemId"]?.let {
|
||||
decoder.json.decodeFromJsonElement(serializer<List<String>>(), it).forEach {
|
||||
val ident = Identifier.tryParse(it)
|
||||
if (ident != null)
|
||||
filters.add(AllowsVanillaItemType(RegistryKey.of(RegistryKeys.ITEM, ident)))
|
||||
}
|
||||
}
|
||||
return filters
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: List<ReforgeEligibilityFilter>) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
|
||||
object Serializer : KSerializer<ReforgeEligibilityFilter> {
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = serializer<JsonElement>().descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): ReforgeEligibilityFilter {
|
||||
val jsonObject = serializer<JsonObject>().deserialize(decoder)
|
||||
jsonObject["internalName"]?.let {
|
||||
return AllowsInternalName(SkyblockId((it as JsonPrimitive).content))
|
||||
}
|
||||
jsonObject["itemType"]?.let {
|
||||
return AllowsItemType(ItemType.ofName((it as JsonPrimitive).content))
|
||||
}
|
||||
jsonObject["minecraftId"]?.let {
|
||||
return AllowsVanillaItemType(RegistryKey.of(RegistryKeys.ITEM,
|
||||
Identifier.of((it as JsonPrimitive).content)))
|
||||
}
|
||||
error("Unknown item type")
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: ReforgeEligibilityFilter) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class AllowsItemType(val itemType: ItemType) : ReforgeEligibilityFilter
|
||||
data class AllowsInternalName(val internalName: SkyblockId) : ReforgeEligibilityFilter
|
||||
data class AllowsVanillaItemType(val minecraftId: RegistryKey<Item>) : ReforgeEligibilityFilter
|
||||
}
|
||||
|
||||
|
||||
val reforgeId get() = nbtModifier ?: ReforgeId(reforgeName.lowercase())
|
||||
|
||||
@Serializable(with = RarityMapped.Serializer::class)
|
||||
sealed interface RarityMapped<T> {
|
||||
fun get(rarity: Rarity?): T?
|
||||
|
||||
class Serializer<T>(
|
||||
val values: KSerializer<T>
|
||||
) : KSerializer<RarityMapped<T>> {
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = JsonElement.serializer().descriptor
|
||||
|
||||
val indirect = MapSerializer(Rarity.serializer(), values)
|
||||
override fun deserialize(decoder: Decoder): RarityMapped<T> {
|
||||
decoder as JsonDecoder
|
||||
val element = decoder.decodeJsonElement()
|
||||
if (element is JsonObject) {
|
||||
return PerRarity(decoder.json.decodeFromJsonElement(indirect, element))
|
||||
} else {
|
||||
return Direct(decoder.json.decodeFromJsonElement(values, element))
|
||||
}
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: RarityMapped<T>) {
|
||||
when (value) {
|
||||
is Direct<T> ->
|
||||
values.serialize(encoder, value.value)
|
||||
|
||||
is PerRarity<T> ->
|
||||
indirect.serialize(encoder, value.values)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Direct<T>(val value: T) : RarityMapped<T> {
|
||||
override fun get(rarity: Rarity?): T {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class PerRarity<T>(val values: Map<Rarity, T>) : RarityMapped<T> {
|
||||
override fun get(rarity: Rarity?): T? {
|
||||
return values[rarity]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
124
src/main/kotlin/repo/ReforgeStore.kt
Normal file
124
src/main/kotlin/repo/ReforgeStore.kt
Normal file
@@ -0,0 +1,124 @@
|
||||
package moe.nea.firmament.repo
|
||||
|
||||
import com.google.gson.JsonElement
|
||||
import com.mojang.serialization.JsonOps
|
||||
import io.github.moulberry.repo.IReloadable
|
||||
import io.github.moulberry.repo.NEURepoFile
|
||||
import io.github.moulberry.repo.NEURepository
|
||||
import io.github.moulberry.repo.NEURepositoryException
|
||||
import io.github.moulberry.repo.data.NEURecipe
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.serializer
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.util.ReforgeId
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.json.KJsonOps
|
||||
import moe.nea.firmament.util.skyblock.ItemType
|
||||
|
||||
object ReforgeStore : ExtraRecipeProvider, IReloadable {
|
||||
override fun provideExtraRecipes(): Iterable<NEURecipe> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
var byType: Map<ItemType, List<Reforge>> = mapOf()
|
||||
var byVanilla: Map<RegistryKey<Item>, List<Reforge>> = mapOf()
|
||||
var byInternalName: Map<SkyblockId, List<Reforge>> = mapOf()
|
||||
var modifierLut = mapOf<ReforgeId, Reforge>()
|
||||
var byReforgeStone = mapOf<SkyblockId, Reforge>()
|
||||
var allReforges = listOf<Reforge>()
|
||||
|
||||
fun findEligibleForItem(itemType: ItemType): List<Reforge> {
|
||||
return byType[itemType] ?: listOf()
|
||||
}
|
||||
|
||||
fun findEligibleForInternalName(internalName: SkyblockId): List<Reforge> {
|
||||
return byInternalName[internalName] ?: listOf()
|
||||
}
|
||||
|
||||
//TODO: return byVanillla
|
||||
override fun reload(repo: NEURepository) {
|
||||
val basicReforges =
|
||||
repo.file("constants/reforges.json")
|
||||
?.kJson(serializer<Map<String, Reforge>>())
|
||||
?.values ?: emptyList()
|
||||
val advancedReforges =
|
||||
repo.file("constants/reforgestones.json")
|
||||
?.kJson(serializer<Map<String, Reforge>>())
|
||||
?.values ?: emptyList()
|
||||
val allReforges = (basicReforges + advancedReforges)
|
||||
modifierLut = allReforges.associateBy { it.reforgeId }
|
||||
byReforgeStone = allReforges.filter { it.reforgeStone != null }
|
||||
.associateBy { it.reforgeStone!! }
|
||||
val byType = mutableMapOf<ItemType, MutableList<Reforge>>()
|
||||
val byVanilla = mutableMapOf<RegistryKey<Item>, MutableList<Reforge>>()
|
||||
val byInternalName = mutableMapOf<SkyblockId, MutableList<Reforge>>()
|
||||
this.byType = byType
|
||||
this.byVanilla = byVanilla
|
||||
this.byInternalName = byInternalName
|
||||
for (reforge in allReforges) {
|
||||
for (eligibleItem in reforge.eligibleItems) {
|
||||
when (eligibleItem) {
|
||||
is Reforge.ReforgeEligibilityFilter.AllowsInternalName -> {
|
||||
byInternalName.getOrPut(eligibleItem.internalName, ::mutableListOf).add(reforge)
|
||||
}
|
||||
|
||||
is Reforge.ReforgeEligibilityFilter.AllowsItemType -> {
|
||||
val actualItemTypes = resolveItemType(eligibleItem.itemType)
|
||||
for (itemType in actualItemTypes) {
|
||||
byType.getOrPut(itemType, ::mutableListOf).add(reforge)
|
||||
}
|
||||
}
|
||||
|
||||
is Reforge.ReforgeEligibilityFilter.AllowsVanillaItemType -> {
|
||||
byVanilla.getOrPut(eligibleItem.minecraftId, ::mutableListOf).add(reforge)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.allReforges = allReforges
|
||||
}
|
||||
|
||||
fun resolveItemType(itemType: ItemType): List<ItemType> {
|
||||
if (ItemType.SWORD == itemType) {
|
||||
return listOf(
|
||||
ItemType.SWORD,
|
||||
ItemType.GAUNTLET,
|
||||
ItemType.LONGSWORD,// TODO: check name
|
||||
ItemType.FISHING_WEAPON,// TODO: check name
|
||||
)
|
||||
}
|
||||
if (itemType == ItemType.ofName("ARMOR")) {
|
||||
return listOf(
|
||||
ItemType.CHESTPLATE,
|
||||
ItemType.LEGGINGS,
|
||||
ItemType.HELMET,
|
||||
ItemType.BOOTS,
|
||||
)
|
||||
}
|
||||
if (itemType == ItemType.EQUIPMENT) {
|
||||
return listOf(
|
||||
ItemType.CLOAK,
|
||||
ItemType.BRACELET,
|
||||
ItemType.NECKLACE,
|
||||
ItemType.BELT,
|
||||
ItemType.GLOVES,
|
||||
)
|
||||
}
|
||||
if (itemType == ItemType.ROD) {
|
||||
return listOf(ItemType.FISHING_ROD, ItemType.FISHING_WEAPON)
|
||||
}
|
||||
return listOf(itemType)
|
||||
}
|
||||
|
||||
fun <T> NEURepoFile.kJson(serializer: KSerializer<T>): T {
|
||||
val rawJson = json(JsonElement::class.java)
|
||||
try {
|
||||
val kJsonElement = JsonOps.INSTANCE.convertTo(KJsonOps.INSTANCE, rawJson)
|
||||
return Firmament.json.decodeFromJsonElement(serializer, kJsonElement)
|
||||
} catch (ex: Exception) {
|
||||
throw NEURepositoryException(path, "Could not decode kotlin JSON element", ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/main/kotlin/repo/RepoItemTypeCache.kt
Normal file
15
src/main/kotlin/repo/RepoItemTypeCache.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
package moe.nea.firmament.repo
|
||||
|
||||
import io.github.moulberry.repo.IReloadable
|
||||
import io.github.moulberry.repo.NEURepository
|
||||
import io.github.moulberry.repo.data.NEUItem
|
||||
import moe.nea.firmament.util.skyblock.ItemType
|
||||
|
||||
object RepoItemTypeCache : IReloadable {
|
||||
|
||||
var byItemType: Map<ItemType?, List<NEUItem>> = mapOf()
|
||||
|
||||
override fun reload(repository: NEURepository) {
|
||||
byItemType = repository.items.items.values.groupBy { ItemType.fromEscapeCodeLore(it.lore.lastOrNull() ?: "") }
|
||||
}
|
||||
}
|
||||
@@ -53,13 +53,16 @@ object RepoManager {
|
||||
var recentlyFailedToUpdateItemList = false
|
||||
|
||||
val essenceRecipeProvider = EssenceRecipeProvider()
|
||||
val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider)
|
||||
val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider, ReforgeStore)
|
||||
|
||||
fun makeNEURepository(path: Path): NEURepository {
|
||||
return NEURepository.of(path).apply {
|
||||
registerReloadListener(ItemCache)
|
||||
registerReloadListener(RepoItemTypeCache)
|
||||
registerReloadListener(ExpLadders)
|
||||
registerReloadListener(ItemNameLookup)
|
||||
registerReloadListener(ReforgeStore)
|
||||
registerReloadListener(essenceRecipeProvider)
|
||||
ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this))
|
||||
registerReloadListener {
|
||||
if (TestUtil.isInTest) return@registerReloadListener
|
||||
@@ -70,7 +73,6 @@ object RepoManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
registerReloadListener(essenceRecipeProvider)
|
||||
registerReloadListener(recipeCache)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,31 @@ import net.minecraft.item.ItemStack
|
||||
import net.minecraft.network.RegistryByteBuf
|
||||
import net.minecraft.network.codec.PacketCodec
|
||||
import net.minecraft.network.codec.PacketCodecs
|
||||
import net.minecraft.text.Style
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.text.TextColor
|
||||
import net.minecraft.util.Formatting
|
||||
import moe.nea.firmament.repo.ItemCache.asItemStack
|
||||
import moe.nea.firmament.repo.ItemCache.withFallback
|
||||
import moe.nea.firmament.util.FirmFormatters
|
||||
import moe.nea.firmament.util.LegacyFormattingCode
|
||||
import moe.nea.firmament.util.ReforgeId
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.directLiteralStringContent
|
||||
import moe.nea.firmament.util.extraAttributes
|
||||
import moe.nea.firmament.util.getReforgeId
|
||||
import moe.nea.firmament.util.getUpgradeStars
|
||||
import moe.nea.firmament.util.grey
|
||||
import moe.nea.firmament.util.mc.appendLore
|
||||
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||
import moe.nea.firmament.util.petData
|
||||
import moe.nea.firmament.util.prepend
|
||||
import moe.nea.firmament.util.skyBlockId
|
||||
import moe.nea.firmament.util.skyblock.ItemType
|
||||
import moe.nea.firmament.util.skyblock.Rarity
|
||||
import moe.nea.firmament.util.skyblockId
|
||||
import moe.nea.firmament.util.useMatch
|
||||
import moe.nea.firmament.util.withColor
|
||||
|
||||
data class SBItemStack constructor(
|
||||
@@ -29,9 +42,9 @@ data class SBItemStack constructor(
|
||||
private var stackSize: Int,
|
||||
private var petData: PetData?,
|
||||
val extraLore: List<Text> = emptyList(),
|
||||
// TODO: grab this star data from nbt if possible
|
||||
val stars: Int = 0,
|
||||
val fallback: ItemStack? = null,
|
||||
val reforge: ReforgeId? = null,
|
||||
) {
|
||||
|
||||
fun getStackSize() = stackSize
|
||||
@@ -68,7 +81,9 @@ data class SBItemStack constructor(
|
||||
skyblockId,
|
||||
RepoManager.getNEUItem(skyblockId),
|
||||
itemStack.count,
|
||||
petData = itemStack.petData?.let { PetData.fromHypixel(it) }
|
||||
petData = itemStack.petData?.let { PetData.fromHypixel(it) },
|
||||
stars = itemStack.getUpgradeStars(),
|
||||
reforge = itemStack.getReforgeId()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -83,6 +98,153 @@ data class SBItemStack constructor(
|
||||
fun passthrough(itemStack: ItemStack): SBItemStack {
|
||||
return SBItemStack(SkyblockId.NULL, null, itemStack.count, null, fallback = itemStack)
|
||||
}
|
||||
|
||||
fun appendEnhancedStats(
|
||||
itemStack: ItemStack,
|
||||
reforgeStats: Map<String, Double>,
|
||||
buffKind: BuffKind,
|
||||
) {
|
||||
val namedReforgeStats = reforgeStats
|
||||
.mapKeysTo(mutableMapOf()) { statIdToName(it.key) }
|
||||
val loreMut = itemStack.loreAccordingToNbt.toMutableList()
|
||||
var statBlockLastIndex = -1
|
||||
for (i in loreMut.indices) {
|
||||
val statLine = parseStatLine(loreMut[i])
|
||||
if (statLine == null && statBlockLastIndex >= 0) {
|
||||
break
|
||||
}
|
||||
if (statLine == null) {
|
||||
continue
|
||||
}
|
||||
statBlockLastIndex = i
|
||||
val statBuff = namedReforgeStats.remove(statLine.statName) ?: continue
|
||||
loreMut[i] = statLine.addStat(statBuff, buffKind).reconstitute()
|
||||
}
|
||||
if (namedReforgeStats.isNotEmpty() && statBlockLastIndex == -1) {
|
||||
loreMut.add(0, Text.literal(""))
|
||||
}
|
||||
// If there is no stat block the statBlockLastIndex falls through to -1
|
||||
// TODO: this is good enough for some items. some other items might have their stats at a different place.
|
||||
for ((statName, statBuff) in namedReforgeStats) {
|
||||
val statLine = StatLine(statName, null).addStat(statBuff, buffKind)
|
||||
loreMut.add(statBlockLastIndex + 1, statLine.reconstitute())
|
||||
}
|
||||
itemStack.loreAccordingToNbt = loreMut
|
||||
}
|
||||
|
||||
data class StatFormatting(
|
||||
val postFix: String,
|
||||
val color: Formatting,
|
||||
)
|
||||
|
||||
val formattingOverrides = mapOf(
|
||||
"Sea Creature Chance" to StatFormatting("%", Formatting.RED),
|
||||
"Strength" to StatFormatting("", Formatting.RED),
|
||||
"Damage" to StatFormatting("", Formatting.RED),
|
||||
"Bonus Attack Speed" to StatFormatting("%", Formatting.RED),
|
||||
"Shot Cooldown" to StatFormatting("s", Formatting.RED),
|
||||
"Ability Damage" to StatFormatting("%", Formatting.RED),
|
||||
"Crit Damage" to StatFormatting("%", Formatting.RED),
|
||||
"Crit Chance" to StatFormatting("%", Formatting.RED),
|
||||
"Ability Damage" to StatFormatting("%", Formatting.RED),
|
||||
"Trophy Fish Chance" to StatFormatting("%", Formatting.GREEN),
|
||||
"Health" to StatFormatting("", Formatting.GREEN),
|
||||
"Defense" to StatFormatting("", Formatting.GREEN),
|
||||
"Fishing Speed" to StatFormatting("", Formatting.GREEN),
|
||||
"Double Hook Chance" to StatFormatting("%", Formatting.GREEN),
|
||||
"Mining Speed" to StatFormatting("", Formatting.GREEN),
|
||||
"Mining Fortune" to StatFormatting("", Formatting.GREEN),
|
||||
"Heat Resistance" to StatFormatting("", Formatting.GREEN),
|
||||
"Swing Range" to StatFormatting("", Formatting.GREEN),
|
||||
"Rift Time" to StatFormatting("", Formatting.GREEN),
|
||||
"Speed" to StatFormatting("", Formatting.GREEN),
|
||||
"Farming Fortune" to StatFormatting("", Formatting.GREEN),
|
||||
"True Defense" to StatFormatting("", Formatting.GREEN),
|
||||
"Mending" to StatFormatting("", Formatting.GREEN),
|
||||
"Foraging Wisdom" to StatFormatting("", Formatting.GREEN),
|
||||
"Farming Wisdom" to StatFormatting("", Formatting.GREEN),
|
||||
"Foraging Fortune" to StatFormatting("", Formatting.GREEN),
|
||||
"Magic Find" to StatFormatting("", Formatting.GREEN),
|
||||
"Ferocity" to StatFormatting("", Formatting.GREEN),
|
||||
"Bonus Pest Chance" to StatFormatting("%", Formatting.GREEN),
|
||||
"Cold Resistance" to StatFormatting("", Formatting.GREEN),
|
||||
"Pet Luck" to StatFormatting("", Formatting.GREEN),
|
||||
"Fear" to StatFormatting("", Formatting.GREEN),
|
||||
"Mana Regen" to StatFormatting("%", Formatting.GREEN),
|
||||
"Rift Damage" to StatFormatting("", Formatting.GREEN),
|
||||
"Hearts" to StatFormatting("", Formatting.GREEN),
|
||||
"Vitality" to StatFormatting("", Formatting.GREEN),
|
||||
// TODO: make this a repo json
|
||||
)
|
||||
|
||||
|
||||
private val statLabelRegex = "(?<statName>.*): ".toPattern()
|
||||
|
||||
enum class BuffKind(
|
||||
val color: Formatting,
|
||||
val prefix: String,
|
||||
val postFix: String,
|
||||
) {
|
||||
REFORGE(Formatting.BLUE, "(", ")"),
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
data class StatLine(
|
||||
val statName: String,
|
||||
val value: Text?,
|
||||
val rest: List<Text> = listOf(),
|
||||
val valueNum: Double? = value?.directLiteralStringContent?.trim(' ', '%', '+')?.toDoubleOrNull()
|
||||
) {
|
||||
fun addStat(amount: Double, buffKind: BuffKind): StatLine {
|
||||
val formattedAmount = FirmFormatters.formatCommas(amount, 1, includeSign = true)
|
||||
return copy(
|
||||
valueNum = (valueNum ?: 0.0) + amount,
|
||||
value = null,
|
||||
rest = rest +
|
||||
listOf(
|
||||
Text.literal(
|
||||
buffKind.prefix + formattedAmount +
|
||||
statFormatting.postFix +
|
||||
buffKind.postFix + " ")
|
||||
.withColor(buffKind.color)))
|
||||
}
|
||||
|
||||
fun formatValue() =
|
||||
Text.literal(FirmFormatters.formatCommas(valueNum ?: 0.0,
|
||||
1,
|
||||
includeSign = true) + statFormatting.postFix + " ")
|
||||
.setStyle(Style.EMPTY.withColor(statFormatting.color))
|
||||
|
||||
val statFormatting = formattingOverrides[statName] ?: StatFormatting("", Formatting.GREEN)
|
||||
private fun abbreviate(abbreviateTo: Int): String {
|
||||
if (abbreviateTo >= statName.length) return statName
|
||||
val segments = statName.split(" ")
|
||||
return segments.joinToString(" ") {
|
||||
it.substring(0, maxOf(1, abbreviateTo / segments.size))
|
||||
}
|
||||
}
|
||||
|
||||
fun reconstitute(abbreviateTo: Int = Int.MAX_VALUE): Text =
|
||||
Text.literal("").setStyle(Style.EMPTY.withItalic(false))
|
||||
.append(Text.literal("${abbreviate(abbreviateTo)}: ").grey())
|
||||
.append(value ?: formatValue())
|
||||
.also { rest.forEach(it::append) }
|
||||
}
|
||||
|
||||
fun statIdToName(statId: String): String {
|
||||
val segments = statId.split("_")
|
||||
return segments.joinToString(" ") { it.replaceFirstChar { it.uppercaseChar() } }
|
||||
}
|
||||
|
||||
private fun parseStatLine(line: Text): StatLine? {
|
||||
val sibs = line.siblings
|
||||
val stat = sibs.firstOrNull() ?: return null
|
||||
if (stat.style.color != TextColor.fromFormatting(Formatting.GRAY)) return null
|
||||
val statLabel = stat.directLiteralStringContent ?: return null
|
||||
val statName = statLabelRegex.useMatch(statLabel) { group("statName") } ?: return null
|
||||
return StatLine(statName, sibs[1], sibs.subList(2, sibs.size))
|
||||
}
|
||||
}
|
||||
|
||||
constructor(skyblockId: SkyblockId, petData: PetData) : this(
|
||||
@@ -133,6 +295,25 @@ data class SBItemStack constructor(
|
||||
}
|
||||
|
||||
|
||||
private fun appendReforgeInfo(
|
||||
itemStack: ItemStack,
|
||||
) {
|
||||
val rarity = Rarity.fromItem(itemStack) ?: return
|
||||
val reforgeId = this.reforge ?: return
|
||||
val reforge = ReforgeStore.modifierLut[reforgeId] ?: return
|
||||
val reforgeStats = reforge.reforgeStats?.get(rarity) ?: mapOf()
|
||||
itemStack.displayNameAccordingToNbt = itemStack.displayNameAccordingToNbt.copy()
|
||||
.prepend(Text.literal(reforge.reforgeName + " ").formatted(Rarity.colourMap[rarity] ?: Formatting.WHITE))
|
||||
val data = itemStack.extraAttributes.copy()
|
||||
data.putString("modifier", reforgeId.id)
|
||||
itemStack.extraAttributes = data
|
||||
appendEnhancedStats(itemStack, reforgeStats, BuffKind.REFORGE)
|
||||
}
|
||||
|
||||
// TODO: avoid instantiating the item stack here
|
||||
val itemType: ItemType? get() = ItemType.fromItemStack(asImmutableItemStack())
|
||||
val rarity: Rarity? get() = Rarity.fromItem(asImmutableItemStack())
|
||||
|
||||
private var itemStack_: ItemStack? = null
|
||||
|
||||
private val itemStack: ItemStack
|
||||
@@ -147,6 +328,7 @@ data class SBItemStack constructor(
|
||||
return@run neuItem.asItemStack(idHint = skyblockId, replacementData)
|
||||
.withFallback(fallback)
|
||||
.copyWithCount(stackSize)
|
||||
.also { appendReforgeInfo(it) }
|
||||
.also { it.appendLore(extraLore) }
|
||||
.also { enhanceStatsByStars(it, stars) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user