test: Add sack util test

This commit is contained in:
Linnea Gräf
2024-11-13 13:40:50 +01:00
parent db87e52938
commit d267913e20
13 changed files with 408 additions and 252 deletions

View File

@@ -7,6 +7,8 @@
*/
import com.google.devtools.ksp.gradle.KspTaskJvm
import com.google.gson.Gson
import com.google.gson.JsonObject
import moe.nea.licenseextractificator.LicenseDiscoveryTask
import moe.nea.mcautotranslations.gradle.CollectTranslations
import net.fabricmc.loom.LoomGradleExtension
@@ -219,7 +221,8 @@ val configuredSourceSet = createIsolatedSourceSet("configured",
val sodiumSourceSet = createIsolatedSourceSet("sodium")
val citResewnSourceSet = createIsolatedSourceSet("citresewn", isEnabled = false) // TODO: Wait for update
val yaclSourceSet = createIsolatedSourceSet("yacl")
val explosiveEnhancementSourceSet = createIsolatedSourceSet("explosiveEnhancement", isEnabled = false) // TODO: wait for their port
val explosiveEnhancementSourceSet =
createIsolatedSourceSet("explosiveEnhancement", isEnabled = false) // TODO: wait for their port
val wildfireGenderSourceSet = createIsolatedSourceSet("wildfireGender", isEnabled = false) // TODO: wait on their port
val modmenuSourceSet = createIsolatedSourceSet("modmenu")
val reiSourceSet = createIsolatedSourceSet("rei")
@@ -344,7 +347,35 @@ mcAutoTranslations {
translationFunctionResolved.set("moe.nea.firmament.util.trResolved")
}
val downloadTestRepo by tasks.registering(RepoDownload::class) {
this.hash.set(project.property("firmament.compiletimerepohash") as String)
}
val updateTestRepo by tasks.registering {
outputs.upToDateWhen { false }
doLast {
val propertiesFile = rootProject.file("gradle.properties")
val json =
Gson().fromJson(uri("https://api.github.com/repos/NotEnoughUpdates/NotEnoughUpdates-REPO/branches/master")
.toURL().readText(), JsonObject::class.java)
val latestSha = json["commit"].asJsonObject["sha"].asString
var text = propertiesFile.readText()
text = text.replace("firmament\\.compiletimerepohash=[^\n]*".toRegex(),
"firmament.compiletimerepohash=$latestSha")
propertiesFile.writeText(text)
}
}
tasks.test {
val wd =file("build/testWorkDir")
workingDir(wd)
dependsOn(downloadTestRepo)
doFirst {
wd.mkdirs()
wd.resolve("config").deleteRecursively()
systemProperty("firmament.testrepo", downloadTestRepo.flatMap { it.outputDirectory.asFile }.map { it.absolutePath }.get())
}
useJUnitPlatform()
}

View File

@@ -0,0 +1,41 @@
import java.net.URI
import java.util.zip.ZipInputStream
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
abstract class RepoDownload : DefaultTask() {
@get:Input
abstract val hash: Property<String>
@get:OutputDirectory
abstract val outputDirectory: DirectoryProperty
init {
outputDirectory.convention(project.layout.buildDirectory.dir("extracted-test-repo"))
}
@TaskAction
fun performDownload() {
val outputDir = outputDirectory.asFile.get().absoluteFile
outputDir.mkdirs()
URI("https://github.com/notEnoughUpdates/notEnoughUpdates-rEPO/archive/${hash.get()}.zip").toURL().openStream()
.let(::ZipInputStream)
.use { zipInput ->
while (true) {
val entry = zipInput.nextEntry ?: break
val destination = outputDir.resolve(
entry.name.substringAfter('/')).absoluteFile
require(outputDir in generateSequence(destination) { it.parentFile })
if (entry.isDirectory) continue
destination.parentFile.mkdirs()
destination.outputStream().use { output ->
zipInput.copyTo(output)
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2023 Linnea Gr<EFBFBD>f <nea@nea.moe>
# SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
#
# SPDX-License-Identifier: CC0-1.0
# suppress inspection "UnusedProperty" for whole file
@@ -9,3 +9,4 @@ loom.platform=fabric
archives_base_name=Firmament
maven_group=moe.nea.firmament
firmament.compiletimerepohash=a6116d945491d7c57c93d43f51250f93d62d8434

View File

@@ -20,6 +20,7 @@ import moe.nea.firmament.util.TimeMark
import moe.nea.firmament.util.WarpUtil
import moe.nea.firmament.util.render.RenderInWorldContext
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.skyblock.SkyBlockItems
object AncestralSpadeSolver : SubscriptionOwner {
var lastDing = TimeMark.farPast()
@@ -29,13 +30,12 @@ object AncestralSpadeSolver : SubscriptionOwner {
var nextGuess: Vec3d? = null
private set
val ancestralSpadeId = SkyblockId("ANCESTRAL_SPADE")
private var lastTeleportAttempt = TimeMark.farPast()
fun isEnabled() =
DianaWaypoints.TConfig.ancestralSpadeSolver
&& SBData.skyblockLocation == SkyBlockIsland.HUB
&& MC.player?.inventory?.containsAny { it.skyBlockId == ancestralSpadeId } == true // TODO: add a reactive property here
&& MC.player?.inventory?.containsAny { it.skyBlockId == SkyBlockItems.ANCESTRAL_SPADE } == true // TODO: add a reactive property here
@Subscribe
fun onKeyBind(event: WorldKeyboardEvent) {

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.repo
import com.mojang.serialization.Dynamic
@@ -30,186 +28,194 @@ 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.LegacyTagParser
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.TestUtil
import moe.nea.firmament.util.mc.appendLore
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.mc.modifyLore
import moe.nea.firmament.util.skyblockId
object ItemCache : IReloadable {
private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap()
private val df = Schemas.getFixer()
val logger = LogManager.getLogger("${Firmament.logger.name}.ItemCache")
var isFlawless = true
private set
private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap()
private val df = Schemas.getFixer()
val logger = LogManager.getLogger("${Firmament.logger.name}.ItemCache")
var isFlawless = true
private set
private fun NEUItem.get10809CompoundTag(): NbtCompound = NbtCompound().apply {
put("tag", LegacyTagParser.parse(nbttag))
putString("id", minecraftItemId)
putByte("Count", 1)
putShort("Damage", damage.toShort())
}
private fun NEUItem.get10809CompoundTag(): NbtCompound = NbtCompound().apply {
put("tag", LegacyTagParser.parse(nbttag))
putString("id", minecraftItemId)
putByte("Count", 1)
putShort("Damage", damage.toShort())
}
private fun NbtCompound.transformFrom10809ToModern(): NbtCompound? =
try {
df.update(
TypeReferences.ITEM_STACK,
Dynamic(NbtOps.INSTANCE, this),
-1,
SharedConstants.getGameVersion().saveVersion.id
).value as NbtCompound
} catch (e: Exception) {
isFlawless = false
logger.error("Could not data fix up $this", e)
null
}
private fun NbtCompound.transformFrom10809ToModern(): NbtCompound? =
try {
df.update(
TypeReferences.ITEM_STACK,
Dynamic(NbtOps.INSTANCE, this),
-1,
SharedConstants.getGameVersion().saveVersion.id
).value as NbtCompound
} catch (e: Exception) {
isFlawless = false
logger.error("Could not data fix up $this", e)
null
}
fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack {
return ItemStack(Items.PAINTING).apply {
setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null"))
appendLore(
listOf(
Text.stringifiedTranslatable(
"firmament.repo.brokenitem",
(neuItem?.skyblockItemId ?: idHint)
)
)
)
}
}
fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack {
return ItemStack(Items.PAINTING).apply {
setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null"))
appendLore(
listOf(
Text.stringifiedTranslatable(
"firmament.repo.brokenitem",
(neuItem?.skyblockItemId ?: idHint)
)
)
)
}
}
private fun NEUItem.asItemStackNow(): ItemStack {
try {
val oldItemTag = get10809CompoundTag()
val modernItemTag = oldItemTag.transformFrom10809ToModern()
?: return brokenItemStack(this)
val itemInstance =
ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
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()
return brokenItemStack(this)
}
}
private fun NEUItem.asItemStackNow(): ItemStack {
try {
val oldItemTag = get10809CompoundTag()
val modernItemTag = oldItemTag.transformFrom10809ToModern()
?: return brokenItemStack(this)
val itemInstance =
ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this)
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()
return brokenItemStack(this)
}
}
fun NEUItem?.asItemStack(idHint: SkyblockId? = null, loreReplacements: Map<String, String>? = null): ItemStack {
if (this == null) return brokenItemStack(null, idHint)
var s = cache[this.skyblockItemId]
if (s == null) {
s = asItemStackNow()
cache[this.skyblockItemId] = s
}
if (!loreReplacements.isNullOrEmpty()) {
s = s.copy()!!
s.applyLoreReplacements(loreReplacements)
s.setCustomName(s.name.applyLoreReplacements(loreReplacements))
}
return s
}
fun NEUItem?.asItemStack(idHint: SkyblockId? = null, loreReplacements: Map<String, String>? = null): ItemStack {
if (this == null) return brokenItemStack(null, idHint)
var s = cache[this.skyblockItemId]
if (s == null) {
s = asItemStackNow()
cache[this.skyblockItemId] = s
}
if (!loreReplacements.isNullOrEmpty()) {
s = s.copy()!!
s.applyLoreReplacements(loreReplacements)
s.setCustomName(s.name.applyLoreReplacements(loreReplacements))
}
return s
}
fun ItemStack.applyLoreReplacements(loreReplacements: Map<String, String>) {
modifyLore { lore ->
lore.map {
it.applyLoreReplacements(loreReplacements)
}
}
}
fun ItemStack.applyLoreReplacements(loreReplacements: Map<String, String>) {
modifyLore { lore ->
lore.map {
it.applyLoreReplacements(loreReplacements)
}
}
}
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 Text.literal(string).styled { this.style }
}
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 Text.literal(string).styled { this.style }
}
fun NEUItem.getIdentifier() = skyblockId.identifier
var job: Job? = null
var job: Job? = null
object ReloadProgressHud : MoulConfigHud(
"repo_reload", HudMeta(HudPosition(0.0, 0.0, 1F), Text.literal("Repo Reload"), 180, 18)) {
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 isEnabled = false
override fun shouldRender(): Boolean {
return isEnabled
}
@get:Bind("current")
var current: Double = 0.0
@get:Bind("current")
var current: Double = 0.0
@get:Bind("label")
var label: String = ""
@get:Bind("label")
var label: String = ""
@get:Bind("max")
var max: Double = 0.0
@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()
}
}
fun reportProgress(label: String, current: Int, max: Int) {
this.label = label
this.current = current.toDouble()
this.max = max.toDouble()
}
}
override fun reload(repository: NEURepository) {
val j = job
if (j != null && j.isActive) {
j.cancel()
}
cache.clear()
isFlawless = true
override fun reload(repository: NEURepository) {
val j = job
if (j != null && j.isActive) {
j.cancel()
}
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
}
}
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
}
}
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"))
itemStack.setSkullOwner(uuid, texture)
return itemStack
}
init {
if (TestUtil.isInTest) {
initialize()
}
}
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"))
itemStack.setSkullOwner(uuid, texture)
return itemStack
}
}
operator fun NbtCompound.set(key: String, value: String) {
putString(key, value)
putString(key, value)
}
operator fun NbtCompound.set(key: String, value: NbtElement) {
put(key, value)
put(key, value)
}

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.repo
import io.github.moulberry.repo.IReloadable
@@ -12,87 +11,91 @@ import moe.nea.firmament.util.skyblockId
object ItemNameLookup : IReloadable {
fun getItemNameChunks(name: String): Set<String> {
return name.removeColorCodes().split(" ").filterTo(mutableSetOf()) { it.isNotBlank() }
}
fun getItemNameChunks(name: String): Set<String> {
return name.removeColorCodes().split(" ").filterTo(mutableSetOf()) { it.isNotBlank() }
}
var nameMap: NavigableMap<String, out Set<SkyblockId>> = TreeMap()
var nameMap: NavigableMap<String, out Set<SkyblockId>> = TreeMap()
override fun reload(repository: NEURepository) {
val nameMap = TreeMap<String, MutableSet<SkyblockId>>()
repository.items.items.values.forEach { item ->
getAllNamesForItem(item).forEach { name ->
val chunks = getItemNameChunks(name)
chunks.forEach { chunk ->
val set = nameMap.getOrPut(chunk, ::mutableSetOf)
set.add(item.skyblockId)
}
}
}
this.nameMap = nameMap
}
override fun reload(repository: NEURepository) {
val nameMap = TreeMap<String, MutableSet<SkyblockId>>()
repository.items.items.values.forEach { item ->
getAllNamesForItem(item).forEach { name ->
val chunks = getItemNameChunks(name)
chunks.forEach { chunk ->
val set = nameMap.getOrPut(chunk, ::mutableSetOf)
set.add(item.skyblockId)
}
}
}
this.nameMap = nameMap
}
fun getAllNamesForItem(item: NEUItem): Set<String> {
val names = mutableSetOf<String>()
names.add(item.displayName)
if (item.displayName.contains("Enchanted Book")) {
val enchantName = item.lore.firstOrNull()
if (enchantName != null) {
names.add(enchantName)
}
}
return names
}
fun getAllNamesForItem(item: NEUItem): Set<String> {
val names = mutableSetOf<String>()
names.add(item.displayName)
if (item.displayName.contains("Enchanted Book")) {
val enchantName = item.lore.firstOrNull()
if (enchantName != null) {
names.add(enchantName)
}
}
return names
}
fun findItemCandidatesByName(name: String): MutableSet<SkyblockId> {
val candidates = mutableSetOf<SkyblockId>()
for (chunk in getItemNameChunks(name)) {
val set = nameMap[chunk] ?: emptySet()
candidates.addAll(set)
}
return candidates
}
fun findItemCandidatesByName(name: String): MutableSet<SkyblockId> {
val candidates = mutableSetOf<SkyblockId>()
for (chunk in getItemNameChunks(name)) {
val set = nameMap[chunk] ?: emptySet()
candidates.addAll(set)
}
return candidates
}
fun guessItemByName(
/**
* The display name of the item. Color codes will be ignored.
*/
name: String,
/**
* Whether the [name] may contain other text, such as reforges, master stars and such.
*/
mayBeMangled: Boolean
): SkyblockId? {
val cleanName = name.removeColorCodes()
return findBestItemFromCandidates(
findItemCandidatesByName(cleanName),
cleanName,
true
)
}
fun guessItemByName(
/**
* The display name of the item. Color codes will be ignored.
*/
name: String,
/**
* Whether the [name] may contain other text, such as reforges, master stars and such.
*/
mayBeMangled: Boolean
): SkyblockId? {
val cleanName = name.removeColorCodes()
return findBestItemFromCandidates(
findItemCandidatesByName(cleanName),
cleanName,
true
)
}
fun findBestItemFromCandidates(
candidates: Iterable<SkyblockId>,
name: String, mayBeMangled: Boolean
): SkyblockId? {
val expectedClean = name.removeColorCodes()
var bestMatch: SkyblockId? = null
var bestMatchLength = -1
for (candidate in candidates) {
val item = RepoManager.getNEUItem(candidate) ?: continue
for (name in getAllNamesForItem(item)) {
val actualClean = name.removeColorCodes()
val matches = if (mayBeMangled) expectedClean == actualClean
else expectedClean.contains(actualClean)
if (!matches) continue
if (actualClean.length > bestMatchLength) {
bestMatch = candidate
bestMatchLength = actualClean.length
}
}
}
return bestMatch
}
fun findBestItemFromCandidates(
candidates: Iterable<SkyblockId>,
name: String, mayBeMangled: Boolean
): SkyblockId? {
val expectedClean = name.removeColorCodes()
var bestMatch: SkyblockId? = null
var bestMatchLength = -1
for (candidate in candidates) {
val item = RepoManager.getNEUItem(candidate) ?: continue
for (name in getAllNamesForItem(item)) {
val actualClean = name.removeColorCodes()
val matches = if (mayBeMangled) expectedClean == actualClean
else expectedClean.contains(actualClean)
if (!matches) continue
if (actualClean.length > bestMatchLength) {
bestMatch = candidate
bestMatchLength = actualClean.length
}
}
}
return bestMatch
}
init {
RepoManager.initialize()
}
}

View File

@@ -5,6 +5,7 @@ import io.github.moulberry.repo.NEURepositoryException
import io.github.moulberry.repo.data.NEUItem
import io.github.moulberry.repo.data.NEURecipe
import io.github.moulberry.repo.data.Rarity
import java.nio.file.Path
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import kotlinx.coroutines.launch
import net.minecraft.client.MinecraftClient
@@ -14,9 +15,11 @@ import moe.nea.firmament.Firmament
import moe.nea.firmament.Firmament.logger
import moe.nea.firmament.events.ReloadRegistrationEvent
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.ErrorUtil
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.tr
object RepoManager {
@@ -49,29 +52,32 @@ object RepoManager {
var recentlyFailedToUpdateItemList = false
val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply {
registerReloadListener(ItemCache)
registerReloadListener(ExpLadders)
registerReloadListener(ItemNameLookup)
ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this))
registerReloadListener {
Firmament.coroutineScope.launch(MinecraftDispatcher) {
if (!trySendClientboundUpdateRecipesPacket()) {
logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
recentlyFailedToUpdateItemList = true
}
}
}
}
val essenceRecipeProvider = EssenceRecipeProvider()
val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider)
init {
neuRepo.registerReloadListener(essenceRecipeProvider)
neuRepo.registerReloadListener(recipeCache)
fun makeNEURepository(path: Path): NEURepository {
return NEURepository.of(path).apply {
registerReloadListener(ItemCache)
registerReloadListener(ExpLadders)
registerReloadListener(ItemNameLookup)
ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this))
registerReloadListener {
if (TestUtil.isInTest) return@registerReloadListener
Firmament.coroutineScope.launch(MinecraftDispatcher) {
if (!trySendClientboundUpdateRecipesPacket()) {
logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.")
recentlyFailedToUpdateItemList = true
}
}
}
registerReloadListener(essenceRecipeProvider)
registerReloadListener(recipeCache)
}
}
lateinit var neuRepo: NEURepository
private set
fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes }
fun getRecipesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.recipes[skyblockId] ?: setOf()
@@ -106,6 +112,11 @@ object RepoManager {
}
}
fun reloadForTest(from: Path) {
neuRepo = makeNEURepository(from)
reload()
}
fun reload() {
try {
ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk",
@@ -114,16 +125,24 @@ object RepoManager {
ItemCache.ReloadProgressHud.isEnabled = true
neuRepo.reload()
} catch (exc: NEURepositoryException) {
ErrorUtil.softError("Failed to reload repository", exc)
MC.sendChat(
tr("firmament.repo.reloadfail",
"Failed to reload repository. This will result in some mod features not working.")
)
ItemCache.ReloadProgressHud.isEnabled = false
exc.printStackTrace()
}
}
private var wasInitialized = false
fun initialize() {
if (wasInitialized) return
wasInitialized = true
System.getProperty("firmament.testrepo")?.let { compTimeRepo ->
reloadForTest(Path.of(compTimeRepo))
return
}
neuRepo = makeNEURepository(RepoDownloadManager.repoSavedLocation)
if (Config.autoUpdate) {
launchAsyncUpdate()
} else {
@@ -131,6 +150,12 @@ object RepoManager {
}
}
init {
if (TestUtil.isInTest) {
initialize()
}
}
fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? {
val parts = skyblockId.neuItem.split(";")
if (parts.size != 2) {

View File

@@ -10,7 +10,7 @@ import moe.nea.firmament.Firmament
@Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame
object ErrorUtil {
var aggressiveErrors = run {
Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") } || Firmament.DEBUG
TestUtil.isInTest || Firmament.DEBUG
|| ErrorUtil::class.java.desiredAssertionStatus()
}

View File

@@ -102,7 +102,7 @@ object MC {
inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*>
inline val window get() = instance.window
inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager
val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup()
val defaultRegistries: RegistryWrapper.WrapperLookup by lazy { BuiltinRegistries.createWrapperLookup() }
inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries
val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getOrThrow(RegistryKeys.ITEM)
var lastWorld: World? = null

View File

@@ -0,0 +1,5 @@
package moe.nea.firmament.util
object TestUtil {
val isInTest = Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") }
}

View File

@@ -60,8 +60,13 @@ object SackUtil {
@Subscribe
fun updateFromChat(event: ProcessChatEvent) {
if (!event.unformattedString.startsWith("[Sacks]")) return
getUpdatesFromMessage(event.text)
}
fun getUpdatesFromMessage(text: Text): List<SackUpdate> {
val update = ChatUpdate()
event.text.siblings.forEach(update::updateFromHoverText)
text.siblings.forEach(update::updateFromHoverText)
return update.updates
}
data class SackUpdate(

View File

@@ -0,0 +1,10 @@
package moe.nea.firmament.util.skyblock
import moe.nea.firmament.util.SkyblockId
object SkyBlockItems {
val ROTTEN_FLESH = SkyblockId("ROTTEN_FLESH")
val ENCHANTED_DIAMOND = SkyblockId("ENCHANTED_DIAMOND")
val DIAMOND = SkyblockId("DIAMOND")
val ANCESTRAL_SPADE = SkyblockId("ANCESTRAL_SPADE")
}

View File

@@ -0,0 +1,29 @@
package moe.nea.firmament.test.util.skyblock
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import moe.nea.firmament.test.testutil.ItemResources
import moe.nea.firmament.util.skyblock.SackUtil
import moe.nea.firmament.util.skyblock.SkyBlockItems
class SackUtilTest {
@Test
fun testOneRottenFlesh() {
Assertions.assertEquals(
listOf(
SackUtil.SackUpdate(SkyBlockItems.ROTTEN_FLESH, "Rotten Flesh", 1)
),
SackUtil.getUpdatesFromMessage(ItemResources.loadText("sacks/gain-rotten-flesh"))
)
}
@Test
fun testAFewRegularItems() {
Assertions.assertEquals(
listOf(
SackUtil.SackUpdate(SkyBlockItems.ROTTEN_FLESH, "Rotten Flesh", 1)
),
SackUtil.getUpdatesFromMessage(ItemResources.loadText("sacks/gain-and-lose-regular"))
)
}
}