aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/repo
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/repo')
-rw-r--r--src/main/kotlin/repo/ExpLadder.kt3
-rw-r--r--src/main/kotlin/repo/ExpensiveItemCacheApi.kt8
-rw-r--r--src/main/kotlin/repo/HypixelStaticData.kt58
-rw-r--r--src/main/kotlin/repo/ItemCache.kt213
-rw-r--r--src/main/kotlin/repo/MiningRepoData.kt131
-rw-r--r--src/main/kotlin/repo/ModernOverlaysData.kt41
-rw-r--r--src/main/kotlin/repo/Reforge.kt18
-rw-r--r--src/main/kotlin/repo/ReforgeStore.kt8
-rw-r--r--src/main/kotlin/repo/RepoDownloadManager.kt203
-rw-r--r--src/main/kotlin/repo/RepoManager.kt104
-rw-r--r--src/main/kotlin/repo/RepoModResourcePack.kt82
-rw-r--r--src/main/kotlin/repo/SBItemStack.kt214
-rw-r--r--src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt18
-rw-r--r--src/main/kotlin/repo/recipes/RecipeLayouter.kt43
-rw-r--r--src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt44
-rw-r--r--src/main/kotlin/repo/recipes/SBEssenceUpgradeRecipeRenderer.kt74
-rw-r--r--src/main/kotlin/repo/recipes/SBForgeRecipeRenderer.kt88
-rw-r--r--src/main/kotlin/repo/recipes/SBReforgeRecipeRenderer.kt167
18 files changed, 1105 insertions, 412 deletions
diff --git a/src/main/kotlin/repo/ExpLadder.kt b/src/main/kotlin/repo/ExpLadder.kt
index fbc9eb8..25a74de 100644
--- a/src/main/kotlin/repo/ExpLadder.kt
+++ b/src/main/kotlin/repo/ExpLadder.kt
@@ -19,7 +19,8 @@ object ExpLadders : IReloadable {
val expInCurrentLevel: Float,
var expTotal: Float,
) {
- val percentageToNextLevel: Float = expInCurrentLevel / expRequiredForNextLevel
+ val percentageToNextLevel: Float = expInCurrentLevel / expRequiredForNextLevel
+ val percentageToMaxLevel: Float = expTotal / expRequiredForMaxLevel
}
data class ExpLadder(
diff --git a/src/main/kotlin/repo/ExpensiveItemCacheApi.kt b/src/main/kotlin/repo/ExpensiveItemCacheApi.kt
new file mode 100644
index 0000000..eef95a6
--- /dev/null
+++ b/src/main/kotlin/repo/ExpensiveItemCacheApi.kt
@@ -0,0 +1,8 @@
+package moe.nea.firmament.repo
+
+/**
+ * Marker for functions that could potentially invoke DFU. Please do not call on a lot of objects at once, or try to make sure the item is cached and fall back to a more gentle function call using [SBItemStack.isWarm] and similar functions.
+ */
+@RequiresOptIn
+@Retention(AnnotationRetention.BINARY)
+annotation class ExpensiveItemCacheApi
diff --git a/src/main/kotlin/repo/HypixelStaticData.kt b/src/main/kotlin/repo/HypixelStaticData.kt
index 181aa70..d6be96f 100644
--- a/src/main/kotlin/repo/HypixelStaticData.kt
+++ b/src/main/kotlin/repo/HypixelStaticData.kt
@@ -1,23 +1,19 @@
package moe.nea.firmament.repo
-import io.ktor.client.call.body
-import io.ktor.client.request.get
import org.apache.logging.log4j.LogManager
-import org.lwjgl.glfw.GLFW
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay
+import kotlinx.coroutines.future.await
import kotlinx.coroutines.launch
-import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.time.Duration.Companion.minutes
import moe.nea.firmament.Firmament
import moe.nea.firmament.apis.CollectionResponse
import moe.nea.firmament.apis.CollectionSkillData
-import moe.nea.firmament.keybindings.IKeyBinding
import moe.nea.firmament.util.SkyblockId
-import moe.nea.firmament.util.async.waitForInput
+import moe.nea.firmament.util.net.HttpUtil
object HypixelStaticData {
private val logger = LogManager.getLogger("Firmament.HypixelStaticData")
@@ -25,7 +21,13 @@ object HypixelStaticData {
private val hypixelApiBaseUrl = "https://api.hypixel.net"
var lowestBin: Map<SkyblockId, Double> = mapOf()
private set
- var bazaarData: Map<SkyblockId, BazaarData> = mapOf()
+ var avg1dlowestBin: Map<SkyblockId, Double> = mapOf()
+ private set
+ var avg3dlowestBin: Map<SkyblockId, Double> = mapOf()
+ private set
+ var avg7dlowestBin: Map<SkyblockId, Double> = mapOf()
+ private set
+ var bazaarData: Map<SkyblockId.BazaarStock, BazaarData> = mapOf()
private set
var collectionData: Map<String, CollectionSkillData> = mapOf()
private set
@@ -56,9 +58,11 @@ object HypixelStaticData {
val products: Map<SkyblockId.BazaarStock, BazaarData> = mapOf(),
)
- fun getPriceOfItem(item: SkyblockId): Double? = bazaarData[item]?.quickStatus?.buyPrice ?: lowestBin[item]
- fun hasBazaarStock(item: SkyblockId): Boolean {
+ fun getPriceOfItem(item: SkyblockId): Double? =
+ bazaarData[SkyblockId.BazaarStock.fromSkyBlockId(item)]?.quickStatus?.buyPrice ?: lowestBin[item]
+
+ fun hasBazaarStock(item: SkyblockId.BazaarStock): Boolean {
return item in bazaarData
}
@@ -74,35 +78,43 @@ object HypixelStaticData {
Firmament.coroutineScope.launch {
while (true) {
logger.info("Updating NEU prices")
- updatePrices()
- delay(10.minutes)
+ fetchPricesFromMoulberry()
+ delay(5.minutes)
+ }
+ }
+ Firmament.coroutineScope.launch {
+ while (true) {
+ logger.info("Updating bazaar prices")
+ fetchBazaarPrices()
+ delay(2.minutes)
}
}
- }
-
- private suspend fun updatePrices() {
- awaitAll(
- Firmament.coroutineScope.async { fetchBazaarPrices() },
- Firmament.coroutineScope.async { fetchPricesFromMoulberry() },
- )
}
private suspend fun fetchPricesFromMoulberry() {
- lowestBin = Firmament.httpClient.get("$moulberryBaseUrl/lowestbin.json")
- .body<Map<SkyblockId, Double>>()
+ lowestBin = HttpUtil.request("$moulberryBaseUrl/lowestbin.json")
+ .forJson<Map<SkyblockId, Double>>().await()
+ avg1dlowestBin = HttpUtil.request("$moulberryBaseUrl/auction_averages_lbin/1day.json")
+ .forJson<Map<SkyblockId, Double>>().await()
+ avg3dlowestBin = HttpUtil.request("$moulberryBaseUrl/auction_averages_lbin/3day.json")
+ .forJson<Map<SkyblockId, Double>>().await()
+ avg7dlowestBin = HttpUtil.request("$moulberryBaseUrl/auction_averages_lbin/7day.json")
+ .forJson<Map<SkyblockId, Double>>().await()
}
private suspend fun fetchBazaarPrices() {
- val response = Firmament.httpClient.get("$hypixelApiBaseUrl/skyblock/bazaar").body<BazaarResponse>()
+ val response = HttpUtil.request("$hypixelApiBaseUrl/skyblock/bazaar").forJson<BazaarResponse>()
+ .await()
if (!response.success) {
logger.warn("Retrieved unsuccessful bazaar data")
}
- bazaarData = response.products.mapKeys { it.key.toRepoId() }
+ bazaarData = response.products
}
private suspend fun updateCollectionData() {
val response =
- Firmament.httpClient.get("$hypixelApiBaseUrl/resources/skyblock/collections").body<CollectionResponse>()
+ HttpUtil.request("$hypixelApiBaseUrl/resources/skyblock/collections").forJson<CollectionResponse>()
+ .await()
if (!response.success) {
logger.warn("Retrieved unsuccessful collection data")
}
diff --git a/src/main/kotlin/repo/ItemCache.kt b/src/main/kotlin/repo/ItemCache.kt
index 9fa0083..be07042 100644
--- a/src/main/kotlin/repo/ItemCache.kt
+++ b/src/main/kotlin/repo/ItemCache.kt
@@ -4,71 +4,83 @@ import com.mojang.serialization.Dynamic
import io.github.moulberry.repo.IReloadable
import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.data.NEUItem
-import io.github.notenoughupdates.moulconfig.xml.Bind
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.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import kotlin.io.path.readText
import kotlin.jvm.optionals.getOrNull
import net.minecraft.SharedConstants
-import net.minecraft.client.resource.language.I18n
-import net.minecraft.component.DataComponentTypes
-import net.minecraft.component.type.NbtComponent
-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.core.component.DataComponents
+import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtOps
-import net.minecraft.nbt.NbtString
-import net.minecraft.text.MutableText
-import net.minecraft.text.Style
-import net.minecraft.text.Text
+import net.minecraft.nbt.StringTag
+import net.minecraft.nbt.Tag
+import net.minecraft.nbt.TagParser
+import net.minecraft.network.chat.Component
+import net.minecraft.network.chat.MutableComponent
+import net.minecraft.network.chat.Style
+import net.minecraft.resources.ResourceLocation
+import net.minecraft.util.datafix.DataFixers
+import net.minecraft.util.datafix.fixes.References
+import net.minecraft.world.item.ItemStack
+import net.minecraft.world.item.Items
+import net.minecraft.world.item.component.CustomData
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.features.debug.ExportedTestConstantMeta
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.MinecraftDispatcher
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.loadItemFromNbt
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.skyblockId
import moe.nea.firmament.util.transformEachRecursively
object ItemCache : IReloadable {
private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap()
- private val df = Schemas.getFixer()
+ private val df = DataFixers.getDataFixer()
val logger = LogManager.getLogger("${Firmament.logger.name}.ItemCache")
var isFlawless = true
private set
- private fun NEUItem.get10809CompoundTag(): NbtCompound = NbtCompound().apply {
+ private fun NEUItem.get10809CompoundTag(): CompoundTag = CompoundTag().apply {
put("tag", LegacyTagParser.parse(nbttag))
putString("id", minecraftItemId)
putByte("Count", 1)
putShort("Damage", damage.toShort())
}
- private fun NbtCompound.transformFrom10809ToModern(): NbtCompound? =
+ @ExpensiveItemCacheApi
+ private fun CompoundTag.transformFrom10809ToModern() = convert189ToModern(this@transformFrom10809ToModern)
+ val currentSaveVersion = SharedConstants.getCurrentVersion().dataVersion().version
+
+ @ExpensiveItemCacheApi
+ fun convert189ToModern(nbtComponent: CompoundTag): CompoundTag? =
try {
df.update(
- TypeReferences.ITEM_STACK,
- Dynamic(NbtOps.INSTANCE, this),
+ References.ITEM_STACK,
+ Dynamic(NbtOps.INSTANCE, nbtComponent),
-1,
- SharedConstants.getGameVersion().saveVersion.id
- ).value as NbtCompound
+ currentSaveVersion
+ ).value as CompoundTag
} catch (e: Exception) {
isFlawless = false
logger.error("Could not data fix up $this", e)
@@ -85,24 +97,24 @@ object ItemCache : IReloadable {
fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack {
return ItemStack(Items.PAINTING).apply {
- setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null"))
+ setCustomName(Component.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null"))
appendLore(
listOf(
- Text.stringifiedTranslatable(
+ Component.translatableEscape(
"firmament.repo.brokenitem",
(neuItem?.skyblockItemId ?: idHint)
)
)
)
- set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(NbtCompound().apply {
- put("ID", NbtString.of(neuItem?.skyblockItemId ?: idHint?.neuItem ?: "null"))
+ set(DataComponents.CUSTOM_DATA, CustomData.of(CompoundTag().apply {
+ put("ID", StringTag.valueOf(neuItem?.skyblockItemId ?: idHint?.neuItem ?: "null"))
}))
set(FirmamentDataComponentTypes.IS_BROKEN, true)
}
}
- fun un189Lore(lore: String): MutableText {
- val base = Text.literal("")
+ fun un189Lore(lore: String): MutableComponent {
+ val base = Component.literal("")
base.setStyle(Style.EMPTY.withItalic(false))
var lastColorCode = Style.EMPTY
var readOffset = 0
@@ -113,7 +125,7 @@ object ItemCache : IReloadable {
}
val text = lore.substring(readOffset, nextCode)
if (text.isNotEmpty()) {
- base.append(Text.literal(text).setStyle(lastColorCode))
+ base.append(Component.literal(text).setStyle(lastColorCode))
}
readOffset = nextCode + 2
if (nextCode + 1 < lore.length) {
@@ -123,25 +135,55 @@ object ItemCache : IReloadable {
if (modernFormatting.isColor) {
lastColorCode = Style.EMPTY.withColor(modernFormatting)
} else {
- lastColorCode = lastColorCode.withFormatting(modernFormatting)
+ lastColorCode = lastColorCode.applyFormat(modernFormatting)
}
}
}
return base
}
+ fun tryFindFromModernFormat(skyblockId: SkyblockId): CompoundTag? {
+ val overlayFile =
+ RepoManager.overlayData.getMostModernReadableOverlay(skyblockId, currentSaveVersion) ?: return null
+ val overlay = TagParser.parseCompoundFully(overlayFile.path.readText())
+ val result = ExportedTestConstantMeta.SOURCE_CODEC.decode(
+ NbtOps.INSTANCE, overlay
+ ).result().getOrNull() ?: return null
+ val meta = result.first
+ return df.update(
+ References.ITEM_STACK,
+ Dynamic(NbtOps.INSTANCE, result.second),
+ meta.dataVersion,
+ currentSaveVersion
+ ).value as CompoundTag
+ }
+
+ @ExpensiveItemCacheApi
private fun NEUItem.asItemStackNow(): ItemStack {
+
try {
+ var modernItemTag = tryFindFromModernFormat(this.skyblockId)
val oldItemTag = get10809CompoundTag()
- val modernItemTag = oldItemTag.transformFrom10809ToModern()
- ?: return brokenItemStack(this)
+ var usedOldNbt = false
+ if (modernItemTag == null) {
+ usedOldNbt = true
+ modernItemTag = oldItemTag.transformFrom10809ToModern()
+ ?: return brokenItemStack(this)
+ }
val itemInstance =
- ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
+ loadItemFromNbt( modernItemTag) ?: return brokenItemStack(this)
+ if (usedOldNbt) {
+ val tag = oldItemTag.getCompound("tag")
+ val extraAttributes = tag.flatMap { it.getCompound("ExtraAttributes") }
+ .getOrNull()
+ if (extraAttributes != null)
+ itemInstance.set(DataComponents.CUSTOM_DATA, CustomData.of(extraAttributes))
+ val itemModel = tag.flatMap { it.getString("ItemModel") }.getOrNull()
+ if (itemModel != null)
+ itemInstance.set(DataComponents.ITEM_MODEL, ResourceLocation.parse(itemModel))
+ }
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))
return itemInstance
} catch (e: Exception) {
e.printStackTrace()
@@ -149,6 +191,11 @@ object ItemCache : IReloadable {
}
}
+ fun hasCacheFor(skyblockId: SkyblockId): Boolean {
+ return skyblockId.neuItem in cache
+ }
+
+ @ExpensiveItemCacheApi
fun NEUItem?.asItemStack(idHint: SkyblockId? = null, loreReplacements: Map<String, String>? = null): ItemStack {
if (this == null) return brokenItemStack(null, idHint)
var s = cache[this.skyblockItemId]
@@ -159,7 +206,7 @@ object ItemCache : IReloadable {
if (!loreReplacements.isNullOrEmpty()) {
s = s.copy()!!
s.applyLoreReplacements(loreReplacements)
- s.setCustomName(s.name.applyLoreReplacements(loreReplacements))
+ s.setCustomName(s.hoverName.applyLoreReplacements(loreReplacements))
}
return s
}
@@ -172,67 +219,59 @@ object ItemCache : IReloadable {
}
}
- fun Text.applyLoreReplacements(loreReplacements: Map<String, String>): Text {
+ fun Component.applyLoreReplacements(loreReplacements: Map<String, String>): Component {
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)
+ Component.literal(string).setStyle(it.style)
}
}
- var job: Job? = null
-
- object ReloadProgressHud : MoulConfigHud(
- "repo_reload", HudMeta(HudPosition(0.0, 0.0, 1F), Text.literal("Repo Reload"), 180, 18)) {
-
-
- var isEnabled = false
- override fun shouldRender(): Boolean {
- return isEnabled
- }
+ var itemRecacheScope: CoroutineScope? = null
- @get:Bind("current")
- var current: Double = 0.0
+ private var recacheSoonSubmitted = mutableSetOf<SkyblockId>()
- @get:Bind("label")
- var label: String = ""
-
- @get:Bind("max")
- var max: Double = 0.0
-
- fun reportProgress(label: String, current: Int, max: Int) {
- this.label = label
- this.current = current.toDouble()
- this.max = max.toDouble()
+ @OptIn(ExpensiveItemCacheApi::class)
+ fun recacheSoon(neuItem: NEUItem) {
+ itemRecacheScope?.launch {
+ if (!withContext(MinecraftDispatcher) {
+ recacheSoonSubmitted.add(neuItem.skyblockId)
+ }) {
+ return@launch
+ }
+ neuItem.asItemStack()
}
}
+ @OptIn(ExpensiveItemCacheApi::class)
override fun reload(repository: NEURepository) {
- val j = job
- if (j != null && j.isActive) {
- j.cancel()
- }
+ val j = itemRecacheScope
+ j?.cancel("New reload invoked")
cache.clear()
isFlawless = true
if (TestUtil.isInTest) return
- job = Firmament.coroutineScope.launch {
- val items = repository.items?.items
- if (items == null) {
- ReloadProgressHud.isEnabled = false
- return@launch
- }
- val recacheItems = I18n.translate("firmament.repo.cache")
- ReloadProgressHud.reportProgress(recacheItems, 0, items.size)
- ReloadProgressHud.isEnabled = true
- var i = 0
- items.values.forEach {
- it.asItemStack() // Rebuild cache
- ReloadProgressHud.reportProgress(recacheItems, i++, items.size)
- }
- ReloadProgressHud.isEnabled = false
+ val newScope =
+ CoroutineScope(
+ Firmament.coroutineScope.coroutineContext +
+ SupervisorJob(Firmament.globalJob) +
+ Dispatchers.Default.limitedParallelism(
+ (Runtime.getRuntime().availableProcessors() / 4).coerceAtLeast(1)
+ )
+ )
+ val items = repository.items?.items
+ newScope.launch {
+ val items = items ?: return@launch
+ items.values.chunked(500).map { chunk ->
+ async {
+ chunk.forEach {
+ it.asItemStack() // Rebuild cache
+ }
+ }
+ }.awaitAll()
}
+ itemRecacheScope = newScope
}
fun coinItem(coinAmount: Int): ItemStack {
@@ -250,7 +289,7 @@ object ItemCache : IReloadable {
"http://textures.minecraft.net/texture/7b951fed6a7b2cbc2036916dec7a46c4a56481564d14f945b6ebc03382766d3b"
}
val itemStack = ItemStack(Items.PLAYER_HEAD)
- itemStack.setCustomName(Text.literal("§r§6" + NumberFormat.getInstance().format(coinAmount) + " Coins"))
+ itemStack.setCustomName(Component.literal("§r§6" + NumberFormat.getInstance().format(coinAmount) + " Coins"))
itemStack.setSkullOwner(uuid, texture)
return itemStack
}
@@ -264,10 +303,10 @@ object ItemCache : IReloadable {
}
-operator fun NbtCompound.set(key: String, value: String) {
+operator fun CompoundTag.set(key: String, value: String) {
putString(key, value)
}
-operator fun NbtCompound.set(key: String, value: NbtElement) {
+operator fun CompoundTag.set(key: String, value: Tag) {
put(key, value)
}
diff --git a/src/main/kotlin/repo/MiningRepoData.kt b/src/main/kotlin/repo/MiningRepoData.kt
new file mode 100644
index 0000000..5b5b016
--- /dev/null
+++ b/src/main/kotlin/repo/MiningRepoData.kt
@@ -0,0 +1,131 @@
+package moe.nea.firmament.repo
+
+import io.github.moulberry.repo.IReloadable
+import io.github.moulberry.repo.NEURepository
+import java.util.Collections
+import java.util.NavigableMap
+import java.util.TreeMap
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
+import kotlinx.serialization.serializer
+import kotlin.streams.asSequence
+import net.minecraft.world.level.block.Block
+import net.minecraft.world.item.BlockItem
+import net.minecraft.world.item.ItemStack
+import net.minecraft.nbt.CompoundTag
+import net.minecraft.network.chat.Component
+import moe.nea.firmament.repo.ReforgeStore.kJson
+import moe.nea.firmament.util.SBData
+import moe.nea.firmament.util.SkyBlockIsland
+import moe.nea.firmament.util.SkyblockId
+import moe.nea.firmament.util.mc.FirmamentDataComponentTypes
+import moe.nea.firmament.util.mc.displayNameAccordingToNbt
+import moe.nea.firmament.util.mc.loadItemFromNbt
+import moe.nea.firmament.util.skyblockId
+
+class MiningRepoData : IReloadable {
+ var customMiningAreas: Map<SkyBlockIsland, CustomMiningArea> = mapOf()
+ private set
+ var customMiningBlocks: List<CustomMiningBlock> = listOf()
+ private set
+ var toolsByBreakingPower: NavigableMap<BreakingPowerKey, SBItemStack> = Collections.emptyNavigableMap()
+ private set
+
+
+ data class BreakingPowerKey(
+ val breakingPower: Int,
+ val itemId: SkyblockId? = null
+ ) {
+ companion object {
+ val COMPARATOR: Comparator<BreakingPowerKey> =
+ Comparator
+ .comparingInt<BreakingPowerKey> { it.breakingPower }
+ .thenComparing(Comparator.comparing(
+ { it.itemId },
+ nullsFirst(Comparator.comparing<SkyblockId, Boolean> { "PICK" in it.neuItem || "BING" in it.neuItem }.thenComparing(Comparator.naturalOrder<SkyblockId>()))))
+ }
+ }
+
+ override fun reload(repo: NEURepository) {
+ customMiningAreas = repo.file("mining/custom_mining_areas.json")
+ ?.kJson(serializer()) ?: mapOf()
+ customMiningBlocks = repo.tree("mining/blocks")
+ .asSequence()
+ .filter { it.path.endsWith(".json") }
+ .map { it.kJson(serializer<CustomMiningBlock>()) }
+ .toList()
+ toolsByBreakingPower = Collections.unmodifiableNavigableMap(
+ repo.items.items
+ .values
+ .asSequence()
+ .map { SBItemStack(it.skyblockId) }
+ .filter { it.breakingPower > 0 }
+ .associateTo(TreeMap<BreakingPowerKey, SBItemStack>(BreakingPowerKey.COMPARATOR)) {
+ BreakingPowerKey(it.breakingPower, it.skyblockId) to it
+ })
+ }
+
+ fun getToolsThatCanBreak(breakingPower: Int): Collection<SBItemStack> {
+ return toolsByBreakingPower.tailMap(BreakingPowerKey(breakingPower, null), true).values
+ }
+
+ @Serializable
+ data class CustomMiningBlock(
+ val breakingPower: Int = 0,
+ val blockStrength: Int = 0,
+ val name: String? = null,
+ val baseDrop: SkyblockId? = null,
+ val blocks189: List<Block189> = emptyList()
+ ) {
+ @Transient
+ val dropItem = baseDrop?.let(::SBItemStack)
+ @OptIn(ExpensiveItemCacheApi::class)
+ private val labeledStack by lazy {
+ dropItem?.asCopiedItemStack()?.also(::markItemStack)
+ }
+
+ private fun markItemStack(itemStack: ItemStack) {
+ itemStack.set(FirmamentDataComponentTypes.CUSTOM_MINING_BLOCK_DATA, this)
+ if (name != null)
+ itemStack.displayNameAccordingToNbt = Component.literal(name)
+ }
+
+ fun getDisplayItem(block: Block): ItemStack {
+ return labeledStack ?: ItemStack(block).also(::markItemStack)
+ }
+ }
+
+ @Serializable
+ data class Block189(
+ val itemId: String,
+ val damage: Short = 0,
+ val onlyIn: List<SkyBlockIsland>? = null,
+ ) {
+ @Transient
+ val block = convertToModernBlock()
+
+ val isCurrentlyActive: Boolean
+ get() = isActiveIn(SBData.skyblockLocation ?: SkyBlockIsland.NIL)
+
+ fun isActiveIn(location: SkyBlockIsland) = onlyIn == null || location in onlyIn
+
+ @OptIn(ExpensiveItemCacheApi::class)
+ private fun convertToModernBlock(): Block? {
+ // TODO: this should be in a shared util, really
+ val newCompound = ItemCache.convert189ToModern(CompoundTag().apply {
+ putString("id", itemId)
+ putShort("Damage", damage)
+ }) ?: return null
+ val itemStack = loadItemFromNbt(newCompound) ?: return null
+ val blockItem = itemStack.item as? BlockItem ?: return null
+ return blockItem.block
+ }
+ }
+
+ @Serializable
+ data class CustomMiningArea(
+ val isSpecialMining: Boolean = true
+ )
+
+
+}
diff --git a/src/main/kotlin/repo/ModernOverlaysData.kt b/src/main/kotlin/repo/ModernOverlaysData.kt
new file mode 100644
index 0000000..543b800
--- /dev/null
+++ b/src/main/kotlin/repo/ModernOverlaysData.kt
@@ -0,0 +1,41 @@
+package moe.nea.firmament.repo
+
+import io.github.moulberry.repo.IReloadable
+import io.github.moulberry.repo.NEURepository
+import java.nio.file.Path
+import kotlin.io.path.extension
+import kotlin.io.path.isDirectory
+import kotlin.io.path.listDirectoryEntries
+import kotlin.io.path.nameWithoutExtension
+import moe.nea.firmament.util.SkyblockId
+
+// TODO: move this over to the repo parser
+class ModernOverlaysData : IReloadable {
+ data class OverlayFile(
+ val version: Int,
+ val path: Path,
+ )
+
+ var overlays: Map<SkyblockId, List<OverlayFile>> = mapOf()
+ override fun reload(repo: NEURepository) {
+ val items = mutableMapOf<SkyblockId, MutableList<OverlayFile>>()
+ repo.baseFolder.resolve("itemsOverlay")
+ .takeIf { it.isDirectory() }
+ ?.listDirectoryEntries()
+ ?.forEach { versionFolder ->
+ val version = versionFolder.fileName.toString().toIntOrNull() ?: return@forEach
+ versionFolder.listDirectoryEntries()
+ .forEach { item ->
+ if (item.extension != "snbt") return@forEach
+ val itemId = item.nameWithoutExtension
+ items.getOrPut(SkyblockId(itemId)) { mutableListOf() }.add(OverlayFile(version, item))
+ }
+ }
+ this.overlays = items
+ }
+
+ fun getOverlayFiles(skyblockId: SkyblockId) = overlays[skyblockId] ?: listOf()
+ fun getMostModernReadableOverlay(skyblockId: SkyblockId, version: Int) = getOverlayFiles(skyblockId)
+ .filter { it.version <= version }
+ .maxByOrNull { it.version }
+}
diff --git a/src/main/kotlin/repo/Reforge.kt b/src/main/kotlin/repo/Reforge.kt
index dc0d93d..5f6506f 100644
--- a/src/main/kotlin/repo/Reforge.kt
+++ b/src/main/kotlin/repo/Reforge.kt
@@ -13,10 +13,10 @@ 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 net.minecraft.world.item.Item
+import net.minecraft.resources.ResourceKey
+import net.minecraft.core.registries.Registries
+import net.minecraft.resources.ResourceLocation
import moe.nea.firmament.util.ReforgeId
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.skyblock.ItemType
@@ -64,9 +64,9 @@ data class Reforge(
}
jsonElement["itemId"]?.let {
decoder.json.decodeFromJsonElement(serializer<List<String>>(), it).forEach {
- val ident = Identifier.tryParse(it)
+ val ident = ResourceLocation.tryParse(it)
if (ident != null)
- filters.add(AllowsVanillaItemType(RegistryKey.of(RegistryKeys.ITEM, ident)))
+ filters.add(AllowsVanillaItemType(ResourceKey.create(Registries.ITEM, ident)))
}
}
return filters
@@ -90,8 +90,8 @@ data class Reforge(
return AllowsItemType(ItemType.ofName((it as JsonPrimitive).content))
}
jsonObject["minecraftId"]?.let {
- return AllowsVanillaItemType(RegistryKey.of(RegistryKeys.ITEM,
- Identifier.of((it as JsonPrimitive).content)))
+ return AllowsVanillaItemType(ResourceKey.create(Registries.ITEM,
+ ResourceLocation.parse((it as JsonPrimitive).content)))
}
error("Unknown item type")
}
@@ -104,7 +104,7 @@ data class Reforge(
data class AllowsItemType(val itemType: ItemType) : ReforgeEligibilityFilter
data class AllowsInternalName(val internalName: SkyblockId) : ReforgeEligibilityFilter
- data class AllowsVanillaItemType(val minecraftId: RegistryKey<Item>) : ReforgeEligibilityFilter
+ data class AllowsVanillaItemType(val minecraftId: ResourceKey<Item>) : ReforgeEligibilityFilter
}
diff --git a/src/main/kotlin/repo/ReforgeStore.kt b/src/main/kotlin/repo/ReforgeStore.kt
index 4c01974..cf8b434 100644
--- a/src/main/kotlin/repo/ReforgeStore.kt
+++ b/src/main/kotlin/repo/ReforgeStore.kt
@@ -9,8 +9,8 @@ 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 net.minecraft.world.item.Item
+import net.minecraft.resources.ResourceKey
import moe.nea.firmament.Firmament
import moe.nea.firmament.util.ReforgeId
import moe.nea.firmament.util.SkyblockId
@@ -23,7 +23,7 @@ object ReforgeStore : ExtraRecipeProvider, IReloadable {
}
var byType: Map<ItemType, List<Reforge>> = mapOf()
- var byVanilla: Map<RegistryKey<Item>, List<Reforge>> = mapOf()
+ var byVanilla: Map<ResourceKey<Item>, List<Reforge>> = mapOf()
var byInternalName: Map<SkyblockId, List<Reforge>> = mapOf()
var modifierLut = mapOf<ReforgeId, Reforge>()
var byReforgeStone = mapOf<SkyblockId, Reforge>()
@@ -52,7 +52,7 @@ object ReforgeStore : ExtraRecipeProvider, IReloadable {
byReforgeStone = allReforges.filter { it.reforgeStone != null }
.associateBy { it.reforgeStone!! }
val byType = mutableMapOf<ItemType, MutableList<Reforge>>()
- val byVanilla = mutableMapOf<RegistryKey<Item>, MutableList<Reforge>>()
+ val byVanilla = mutableMapOf<ResourceKey<Item>, MutableList<Reforge>>()
val byInternalName = mutableMapOf<SkyblockId, MutableList<Reforge>>()
this.byType = byType
this.byVanilla = byVanilla
diff --git a/src/main/kotlin/repo/RepoDownloadManager.kt b/src/main/kotlin/repo/RepoDownloadManager.kt
index 3efd83b..adbe36e 100644
--- a/src/main/kotlin/repo/RepoDownloadManager.kt
+++ b/src/main/kotlin/repo/RepoDownloadManager.kt
@@ -1,11 +1,5 @@
-
-
package moe.nea.firmament.repo
-import io.ktor.client.call.body
-import io.ktor.client.request.get
-import io.ktor.client.statement.bodyAsChannel
-import io.ktor.utils.io.copyTo
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Path
@@ -13,6 +7,7 @@ import java.nio.file.StandardOpenOption
import java.util.zip.ZipInputStream
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers.IO
+import kotlinx.coroutines.future.await
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import kotlin.io.path.createDirectories
@@ -23,106 +18,112 @@ import kotlin.io.path.readText
import kotlin.io.path.writeText
import moe.nea.firmament.Firmament
import moe.nea.firmament.Firmament.logger
+import moe.nea.firmament.repo.RepoDownloadManager.latestSavedVersionHash
import moe.nea.firmament.util.iterate
+import moe.nea.firmament.util.net.HttpUtil
object RepoDownloadManager {
- val repoSavedLocation = Firmament.DATA_DIR.resolve("repo-extracted")
- val repoMetadataLocation = Firmament.DATA_DIR.resolve("loaded-repo-sha.txt")
-
- private fun loadSavedVersionHash(): String? =
- if (repoSavedLocation.exists()) {
- if (repoMetadataLocation.exists()) {
- try {
- repoMetadataLocation.readText().trim()
- } catch (e: IOException) {
- null
- }
- } else {
- null
- }
- } else null
-
- private fun saveVersionHash(versionHash: String) {
- latestSavedVersionHash = versionHash
- repoMetadataLocation.writeText(versionHash)
- }
-
- var latestSavedVersionHash: String? = loadSavedVersionHash()
- private set
-
- @Serializable
- private class GithubCommitsResponse(val sha: String)
-
- private suspend fun requestLatestGithubSha(): String? {
- if (RepoManager.Config.branch == "prerelease") {
- Repo