aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle.kts35
-rw-r--r--buildSrc/build.gradle.kts30
-rw-r--r--buildSrc/src/FabricModTransform.kt80
-rw-r--r--gradle/libs.versions.toml5
-rw-r--r--src/main/kotlin/features/debug/PowerUserTools.kt1
-rw-r--r--src/main/kotlin/features/debug/itemeditor/ItemExporter.kt70
-rw-r--r--src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt14
-rw-r--r--src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt40
-rw-r--r--src/main/kotlin/util/SkyblockId.kt7
-rw-r--r--src/main/kotlin/util/StringUtil.kt6
-rw-r--r--src/main/resources/legacy_data/effects.json140
-rw-r--r--testagent/build.gradle.kts2
12 files changed, 381 insertions, 49 deletions
diff --git a/build.gradle.kts b/build.gradle.kts
index 3a72ed0..065925a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -6,6 +6,7 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.google.common.hash.Hashing
import com.google.devtools.ksp.gradle.KspAATask
import com.google.gson.Gson
@@ -29,7 +30,6 @@ plugins {
// alias(libs.plugins.loom)
// TODO: use arch loom once they update to 1.8
id("fabric-loom") version "1.10.1"
- alias(libs.plugins.shadow)
id("moe.nea.licenseextractificator")
alias(libs.plugins.mcAutoTranslations)
}
@@ -130,6 +130,9 @@ val collectTranslations by tasks.registering(CollectTranslations::class) {
this.classes.from(sourceSets.main.get().kotlin.classesDirectory)
}
+val shadowJar = tasks.register("shadowJar", ShadowJar::class)
+val mergedSourceSetsJar = tasks.register("mergedSourceSetsJar", ShadowJar::class)
+
val compatSourceSets: MutableSet<SourceSet> = mutableSetOf()
fun createIsolatedSourceSet(name: String, path: String = "compat/$name", isEnabled: Boolean = true): SourceSet {
val ss = sourceSets.create(name) {
@@ -178,7 +181,7 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name", isEnabl
(ss.implementationConfigurationName)(project.files(tasks.compileKotlin.map { it.destinationDirectory }))
(ss.implementationConfigurationName)(project.files(tasks.compileJava.map { it.destinationDirectory }))
}
- tasks.shadowJar {
+ mergedSourceSetsJar.configure {
from(ss.output)
}
// TODO: figure out why inheritances are not being respected by tiny kotlin names
@@ -268,8 +271,7 @@ dependencies {
nonModImplentation("com.google.auto.service:auto-service-annotations:1.1.1")
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.2.0")
include(libs.manninghamMills)
- include(libs.moulconfig)
-
+ shadowMe(libs.moulconfig)
annotationProcessor(libs.mixinextras)
nonModImplentation(libs.mixinextras)
@@ -437,22 +439,33 @@ tasks.jar {
destinationDirectory.set(layout.buildDirectory.dir("badjars"))
archiveClassifier.set("slim")
}
-
-tasks.shadowJar {
+mergedSourceSetsJar.configure {
+ from(zipTree(tasks.jar.flatMap { it.archiveFile }))
+ destinationDirectory.set(layout.buildDirectory.dir("badjars"))
+ archiveClassifier.set("merged-source-sets")
+ mergeServiceFiles()
+}
+shadowJar.configure {
+ from(zipTree(tasks.remapJar.flatMap { it.archiveFile }))
configurations = listOf(shadowMe)
- archiveClassifier.set("dev")
+ archiveClassifier.set("")
relocate("io.github.moulberry.repo", "moe.nea.firmament.deps.repo")
- destinationDirectory.set(layout.buildDirectory.dir("badjars"))
+ relocate("io.github.notenoughupdates.moulconfig", "moe.nea.firmament.deps.moulconfig")
mergeServiceFiles()
+ transform<FabricModTransform>()
}
tasks.remapJar {
// injectAccessWidener.set(true)
- inputFile.set(tasks.shadowJar.flatMap { it.archiveFile })
- dependsOn(tasks.shadowJar)
- archiveClassifier.set("")
+ inputFile.set(mergedSourceSetsJar.flatMap { it.archiveFile })
+ dependsOn(mergedSourceSetsJar)
+ destinationDirectory.set(layout.buildDirectory.dir("badjars"))
+ archiveClassifier.set("remapped")
}
+tasks.assemble { dependsOn(shadowJar) }
+
+
tasks.processResources {
val replacements = listOf(
"version" to project.version.toString(),
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 54719bc..1b2542b 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -3,25 +3,27 @@
// SPDX-License-Identifier: CC0-1.0
plugins {
- kotlin("jvm") version "2.1.0"
- `kotlin-dsl`
+ kotlin("jvm") version "2.1.0"
+ `kotlin-dsl`
}
repositories {
- mavenCentral()
- maven {
- name = "jitpack"
- url = uri("https://jitpack.io")
- }
+ mavenCentral()
+ maven {
+ name = "jitpack"
+ url = uri("https://jitpack.io")
+ }
}
dependencies {
- implementation("com.github.romangraef:neaslicenseextractificator:1.1.0")
- implementation("com.google.code.gson:gson:2.10.1")
+ implementation("com.github.romangraef:neaslicenseextractificator:1.1.0")
+ api("com.gradleup.shadow:shadow-gradle-plugin:9.0.0-rc1")
+ implementation("net.fabricmc:access-widener:2.1.0")
+ implementation("com.google.code.gson:gson:2.10.1")
}
sourceSets {
- main {
- kotlin {
- srcDir(file("src"))
- }
- }
+ main {
+ kotlin {
+ srcDir(file("src"))
+ }
+ }
}
diff --git a/buildSrc/src/FabricModTransform.kt b/buildSrc/src/FabricModTransform.kt
new file mode 100644
index 0000000..53affbe
--- /dev/null
+++ b/buildSrc/src/FabricModTransform.kt
@@ -0,0 +1,80 @@
+import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
+import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
+import com.google.gson.Gson
+import com.google.gson.JsonObject
+import com.google.gson.JsonPrimitive
+import java.io.Serializable
+import net.fabricmc.accesswidener.AccessWidenerReader
+import net.fabricmc.accesswidener.AccessWidenerWriter
+import org.apache.tools.zip.ZipEntry
+import org.apache.tools.zip.ZipOutputStream
+import org.gradle.api.file.FileTreeElement
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Internal
+
+open class FabricModTransform : ResourceTransformer {
+
+ enum class AccessWidenerInclusion : Serializable {
+ ALL,
+ NONE,
+ }
+
+ @get:Input
+ var mergeAccessWideners: AccessWidenerInclusion = AccessWidenerInclusion.ALL
+
+ @get:Internal
+ internal var mergedFmj: JsonObject? = null
+
+ @get:Internal
+ internal val foundAccessWideners = AccessWidenerWriter()
+
+ @get:Internal
+ internal var foundAnyAccessWidener = false
+
+ override fun canTransformResource(element: FileTreeElement): Boolean {
+ if (mergeAccessWideners == AccessWidenerInclusion.ALL && element.name.endsWith(".accesswidener"))
+ return true
+ return element.path == "fabric.mod.json"
+ }
+
+ override fun transform(context: TransformerContext) {
+ if (context.path.endsWith(".accesswidener")) {
+ foundAnyAccessWidener = true
+ // TODO: allow filtering for only those mentioned in a fabric.mod.json, potentially
+ context.inputStream.use { stream ->
+ AccessWidenerReader(foundAccessWideners).read(stream.bufferedReader())
+ }
+ return
+ }
+ // TODO: mixins.json relocations
+ val fmj = context.inputStream.use { stream ->
+ Gson().fromJson(stream.bufferedReader(), JsonObject::class.java)
+ }
+ val mergedFmj = this.mergedFmj
+ println("${fmj["id"]} is first? ${mergedFmj == null}")
+ if (mergedFmj == null) {
+ this.mergedFmj = fmj
+ } else {
+ // TODO: merge stuff
+ }
+ }
+
+ override fun hasTransformedResource(): Boolean {
+ return mergedFmj != null
+ }
+
+ override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {
+ val mergedFmj = mergedFmj!!
+ if (foundAnyAccessWidener) {
+ val awFile = mergedFmj["accessWidener"]
+ require(awFile is JsonPrimitive && awFile.isString)
+ os.putNextEntry(ZipEntry(awFile.asString))
+ os.write(foundAccessWideners.write())
+ os.closeEntry()
+ }
+ os.putNextEntry(ZipEntry("fabric.mod.json"))
+ os.write(mergedFmj.toString().toByteArray())
+ os.closeEntry()
+ }
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index e4f39e8..f536faf 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -40,6 +40,8 @@ ncr = "Fabric-1.21.5-v2.12.0"
# Update from https://modrinth.com/mod/female-gender/versions?l=fabric
femalegender = "4.3.4+1.21.5"
+shadow = "8.3.8"
+
# Update from https://modrinth.com/mod/explosive-enhancement/versions?l=fabric
explosiveenhancement = "1.2.3-1.21.0"
@@ -135,7 +137,7 @@ femalegender = { module = "maven.modrinth:female-gender", version.ref = "femaleg
jade = { module = "maven.modrinth:jade", version.ref = "jade" }
yacl = { module = "dev.isxander:yet-another-config-lib", version.ref = "yacl" }
basicMath = { module = "me.shedaniel.cloth:basic-math", version.ref = "basicMath" }
-
+shadow = { module = "com.gradleup.shadow:shadow-gradle-plugin", version.ref = "shadow" }
classTransform-mixinsTranslator = { module = "net.lenni0451.classtransform:mixinstranslator", version.ref = "classtransform" }
classTransform-core = { module = "net.lenni0451.classtransform:core", version.ref = "classtransform" }
@@ -162,5 +164,4 @@ kotlin_plugin_serialization = { id = "org.jetbrains.kotlin.plugin.serialization"
kotlin_plugin_powerassert = { id = "org.jetbrains.kotlin.plugin.power-assert", version.ref = "kotlin" }
kotlin_plugin_ksp = { id = "com.google.devtools.ksp", version.ref = "kotlin_ksp" }
loom = { id = "dev.architectury.loom", version.ref = "loom" }
-shadow = { id = "com.github.johnrengelman.shadow", version = "8.1.1" }
mcAutoTranslations = { id = "moe.nea.mc-auto-translations", version.ref = "mcAutoTranslations" }
diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt
index 7c1df3f..1a7b2cf 100644
--- a/src/main/kotlin/features/debug/PowerUserTools.kt
+++ b/src/main/kotlin/features/debug/PowerUserTools.kt
@@ -59,6 +59,7 @@ object PowerUserTools : FirmamentFeature {
val exportItemStackToRepo by keyBindingWithDefaultUnbound("export-item-stack")
val exportUIRecipes by keyBindingWithDefaultUnbound("export-recipe")
val exportNpcLocation by keyBindingWithDefaultUnbound("export-npc-location")
+ val highlightNonOverlayItems by toggle("highlight-non-overlay") { false }
}
override val config
diff --git a/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt b/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
index 37875fb..c521b5a 100644
--- a/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
+++ b/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
@@ -1,6 +1,5 @@
package moe.nea.firmament.features.debug.itemeditor
-import com.mojang.brigadier.arguments.StringArgumentType
import kotlinx.coroutines.launch
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
@@ -19,13 +18,14 @@ import net.minecraft.nbt.NbtString
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
+import moe.nea.firmament.commands.RestArgumentType
import moe.nea.firmament.commands.get
-import moe.nea.firmament.commands.suggestsList
import moe.nea.firmament.commands.thenArgument
import moe.nea.firmament.commands.thenExecute
import moe.nea.firmament.commands.thenLiteral
import moe.nea.firmament.events.CommandEvent
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
+import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.debug.DeveloperFeatures
import moe.nea.firmament.features.debug.ExportedTestConstantMeta
import moe.nea.firmament.features.debug.PowerUserTools
@@ -40,6 +40,7 @@ import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.mc.toNbtList
+import moe.nea.firmament.util.render.drawGuiTexture
import moe.nea.firmament.util.setSkyBlockId
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.tr
@@ -47,6 +48,7 @@ import moe.nea.firmament.util.tr
object ItemExporter {
fun exportItem(itemStack: ItemStack): Text {
+ nonOverlayCache.clear()
val exporter = LegacyItemExporter.createExporter(itemStack)
var json = exporter.exportJson()
val fileName = json.jsonObject["internalname"]!!.jsonPrimitive.content
@@ -116,25 +118,42 @@ object ItemExporter {
fun onCommand(event: CommandEvent.SubCommand) {
event.subcommand(DeveloperFeatures.DEVELOPER_SUBCOMMAND) {
thenLiteral("reexportlore") {
- thenArgument("itemid", StringArgumentType.string()) { itemid ->
- suggestsList { RepoManager.neuRepo.items.items.keys }
+ thenArgument("itemid", RestArgumentType) { itemid ->
+ suggests { ctx, builder ->
+ val spaceIndex = builder.remaining.lastIndexOf(" ")
+ val (before, after) =
+ if (spaceIndex < 0) Pair("", builder.remaining)
+ else Pair(
+ builder.remaining.substring(0, spaceIndex + 1),
+ builder.remaining.substring(spaceIndex + 1)
+ )
+ RepoManager.neuRepo.items.items.keys
+ .asSequence()
+ .filter { it.startsWith(after, ignoreCase = true) }
+ .forEach {
+ builder.suggest(before + it)
+ }
+
+ builder.buildFuture()
+ }
thenExecute {
- val itemid = SkyblockId(get(itemid))
- if (pathFor(itemid).notExists()) {
+ for (itemid in get(itemid).split(" ").map { SkyblockId(it) }) {
+ if (pathFor(itemid).notExists()) {
+ MC.sendChat(
+ tr(
+ "firmament.repo.export.relore.fail",
+ "Could not find json file to relore for ${itemid}"
+ )
+ )
+ }
+ fixLoreNbtFor(itemid)
MC.sendChat(
tr(
- "firmament.repo.export.relore.fail",
- "Could not find json file to relore for ${itemid}"
+ "firmament.repo.export.relore",
+ "Updated lore / display name for $itemid"
)
)
}
- fixLoreNbtFor(itemid)
- MC.sendChat(
- tr(
- "firmament.repo.export.relore",
- "Updated lore / display name for $itemid"
- )
- )
}
}
thenLiteral("all") {
@@ -188,6 +207,27 @@ object ItemExporter {
}
}
+ val nonOverlayCache = mutableMapOf<SkyblockId, Boolean>()
+
+ @Subscribe
+ fun onRender(event: SlotRenderEvents.Before) {
+ if (!PowerUserTools.TConfig.highlightNonOverlayItems) {
+ return
+ }
+ val stack = event.slot.stack ?: return
+ val isExported = nonOverlayCache.getOrPut(stack.skyBlockId ?: return) {
+ RepoDownloadManager.repoSavedLocation.resolve("itemsOverlay")
+ .resolve(ExportedTestConstantMeta.current.dataVersion.toString())
+ .resolve("${stack.skyBlockId}.snbt")
+ .exists()
+ }
+ if (!isExported)
+ event.context.drawGuiTexture(
+ Firmament.identifier("selected_pet_background"),
+ event.slot.x, event.slot.y, 16, 16,
+ )
+ }
+
fun exportStub(skyblockId: SkyblockId, title: String, extra: (ItemStack) -> Unit = {}) {
exportItem(ItemStack(Items.PLAYER_HEAD).also {
it.displayNameAccordingToNbt = Text.literal(title)
diff --git a/src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt b/src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt
index c0f48ca..bc8c618 100644
--- a/src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt
+++ b/src/main/kotlin/features/debug/itemeditor/LegacyItemData.kt
@@ -9,6 +9,7 @@ import moe.nea.firmament.Firmament
import moe.nea.firmament.repo.ExpensiveItemCacheApi
import moe.nea.firmament.repo.ItemCache
import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.StringUtil.camelWords
/**
* Load data based on [prismarine.js' 1.8 item data](https://github.com/PrismarineJS/minecraft-data/blob/master/data/pc/1.8/items.json)
@@ -58,6 +59,7 @@ object LegacyItemData {
val enchantmentLut = enchantmentData.associateBy { Identifier.ofVanilla(it.name) }
val itemDat = getLegacyData<List<ItemData>>("items")
+
@OptIn(ExpensiveItemCacheApi::class) // This is fine, we get loaded in a thread.
val itemLut = itemDat.flatMap { item ->
item.allVariants().map { legacyItemType ->
@@ -72,4 +74,16 @@ object LegacyItemData {
}
}.toMap()
+ @Serializable
+ data class LegacyEffect(
+ val id: Int,
+ val name: String,
+ val displayName: String,
+ val type: String
+ )
+
+ val effectList = getLegacyData<List<LegacyEffect>>("effects")
+ .associateBy {
+ it.name.camelWords().map { it.trim().lowercase() }.joinToString("_")
+ }
}
diff --git a/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt b/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt
index 3cd1ce8..ad03b16 100644
--- a/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt
+++ b/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt
@@ -7,9 +7,11 @@ import kotlinx.serialization.json.put
import kotlin.concurrent.thread
import net.minecraft.component.DataComponentTypes
import net.minecraft.item.ItemStack
+import net.minecraft.nbt.NbtByte
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtElement
import net.minecraft.nbt.NbtInt
+import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtOps
import net.minecraft.nbt.NbtString
import net.minecraft.text.Text
@@ -36,8 +38,9 @@ import moe.nea.firmament.util.unformattedString
class LegacyItemExporter private constructor(var itemStack: ItemStack) {
init {
- require(!itemStack.isEmpty)
+ require(!itemStack.isEmpty)
}
+
var lore = itemStack.loreAccordingToNbt
var name = itemStack.displayNameAccordingToNbt
val extraAttribs = itemStack.extraAttributes.copy()
@@ -133,24 +136,55 @@ class LegacyItemExporter private constructor(var itemStack: ItemStack) {
legacyNbt.put("HideFlags", NbtInt.of(254))
copyUnbreakable()
copyItemModel()
+ copyPotion()
copyExtraAttributes()
copyLegacySkullNbt()
copyDisplay()
+ copyColour()
copyEnchantments()
copyEnchantGlint()
// TODO: copyDisplay
}
+ private fun copyPotion() {
+ val effects = itemStack.get(DataComponentTypes.POTION_CONTENTS) ?: return
+ legacyNbt.put("CustomPotionEffects", NbtList().also {
+ effects.effects.forEach { effect ->
+ val effectId = effect.effectType.key.get().value.path
+ val duration = effect.duration
+ val legacyId = LegacyItemData.effectList[effectId]!!
+
+ it.add(NbtCompound().apply {
+ put("Ambient", NbtByte.of(false))
+ put("Duration", NbtInt.of(duration))
+ put("Id", NbtByte.of(legacyId.id.toByte()))
+ put("Amplifier", NbtByte.of(effect.amplifier.toByte()))
+ })
+ }
+ })
+ }
+
+ fun NbtCompound.getOrPutCompound(name: String): NbtCompound {
+ val compound = getCompoundOrEmpty(name)
+ put(name, compound)
+ return compound
+ }
+
+ private fun copyColour() {
+ val leatherTint = itemStack.get(DataComponentTypes.DYED_COLOR) ?: return
+ legacyNbt.getOrPutCompound("display").put("color", NbtInt.of(leatherTint.rgb))
+ }
+
private fun copyItemModel() {
val itemModel = itemStack.get(DataComponentTypes.ITEM_MODEL) ?: return
legacyNbt.put("ItemModel", NbtString.of(itemModel.toString()))
}
private fun copyDisplay() {
- legacyNbt.put("display", NbtCompound().apply {
+ legacyNbt.getOrPutCompound("display").apply {
put("Lore", lore.map { NbtString.of(it.getLegacyFormatString(trimmed = true)) }.toNbtList())
putString("Name", name.getLegacyFormatString(trimmed = true))
- })
+ }
}
fun exportModernSnbt(): NbtElement {
diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt
index b4d583a..051ca86 100644
--- a/src/main/kotlin/util/SkyblockId.kt
+++ b/src/main/kotlin/util/SkyblockId.kt
@@ -251,10 +251,11 @@ val ItemStack.skyBlockId: SkyblockId?
val potionName = extraAttributes.getString("potion_name").getOrNull()
val potionLevel = extraAttributes.getInt("potion_level").getOrNull()
val potionType = extraAttributes.getString("potion_type").getOrNull()
+ fun String.potionNormalize() = uppercase().replace(" ", "_")
when {
- potionName != null -> SkyblockId("POTION_${potionName.uppercase()};$potionLevel")
- potionData != null -> SkyblockId("POTION_${potionData.uppercase()};$potionLevel")
- potionType != null -> SkyblockId("POTION_${potionType.uppercase()}")
+ potionName != null -> SkyblockId("POTION_${potionName.potionNormalize()};$potionLevel")
+ potionData != null -> SkyblockId("POTION_${potionData.potionNormalize()};$potionLevel")
+ potionType != null -> SkyblockId("POTION_${potionType.potionNormalize()}")
else -> SkyblockId("WATER_BOTTLE")
}
}
diff --git a/src/main/kotlin/util/StringUtil.kt b/src/main/kotlin/util/StringUtil.kt
index dc98dc0..50c5367 100644
--- a/src/main/kotlin/util/StringUtil.kt
+++ b/src/main/kotlin/util/StringUtil.kt
@@ -5,6 +5,12 @@ object StringUtil {
return splitToSequence(" ") // TODO: better boundaries
}
+ fun String.camelWords(): Sequence<String> {
+ return splitToSequence(camelWordStart)
+ }
+
+ private val camelWordStart = Regex("((?<=[a-z])(?=[A-Z]))| ")
+
fun parseIntWithComma(string: String): Int {
return string.replace(",", "").toInt()
}
diff --git a/src/main/resources/legacy_data/effects.json b/src/main/resources/legacy_data/effects.json
new file mode 100644
index 0000000..0b885b5
--- /dev/null
+++ b/src/main/resources/legacy_data/effects.json
@@ -0,0 +1,140 @@
+[
+ {
+ "id": 1,
+ "name": "Speed",
+ "displayName": "Speed",
+ "type": "good"
+ },
+ {
+ "id": 2,
+ "name": "Slowness",
+ "displayName": "Slowness",
+ "type": "bad"
+ },
+ {
+ "id": 3,
+ "name": "Haste",
+ "displayName": "Haste",
+ "type": "good"
+ },
+ {
+ "id": 4,
+ "name": "MiningFatigue",
+ "displayName": "Mining Fatigue",
+ "type": "bad"
+ },
+ {
+ "id": 5,
+ "name": "Strength",
+ "displayName": "Strength",
+ "type": "good"
+ },
+ {
+ "id": 6,
+ "name": "InstantHealth",
+ "displayName": "Instant Health",
+ "type": "good"
+ },
+ {
+ "id": 7,
+ "name": "InstantDamage",
+ "displayName": "Instant Damage",
+ "type": "bad"
+ },
+ {
+ "id": 8,
+ "name": "JumpBoost",
+ "displayName": "Jump Boost",
+ "type": "good"
+ },
+ {
+ "id": 9,
+ "name": "Nausea",
+ "displayName": "Nausea",
+ "type": "bad"
+ },
+ {
+ "id": 10,
+ "name": "Regeneration",
+ "displayName": "Regeneration",
+ "type": "good"
+ },
+ {
+ "id": 11,
+ "name": "Resistance",
+ "displayName": "Resistance",
+ "type": "good"
+ },
+ {
+ "id": 12,
+ "name": "FireResistance",
+ "displayName": "Fire Resistance",
+ "type": "good"
+ },
+ {
+ "id": 13,
+ "name": "WaterBreathing",
+ "displayName": "Water Breathing",
+ "type": "good"
+ },
+ {
+ "id": 14,
+ "name": "Invisibility",
+ "displayName": "Invisibility",
+ "type": "good"
+ },
+ {
+ "id": 15,
+ "name": "Blindness",
+ "displayName": "Blindness",
+ "type": "bad"
+ },
+ {
+ "id": 16,
+ "name": "NightVision",
+ "displayName": "Night Vision",
+ "type": "good"
+ },
+ {
+ "id": 17,
+ "name": "Hunger",
+ "displayName": "Hunger",
+ "type": "bad"
+ },
+ {
+ "id": 18,
+ "name": "Weakness",
+ "displayName": "Weakness",
+ "type": "bad"
+ },
+ {
+ "id": 19,
+ "name": "Poison",
+ "displayName": "Poison",
+ "type": "bad"
+ },
+ {
+ "id": 20,
+ "name": "Wither",
+ "displayName": "Wither",
+ "type": "bad"
+ },
+ {
+ "id": 21,
+ "name": "HealthBoost",
+ "displayName": "Health Boost",
+ "type": "good"
+ },
+ {
+ "id": 22,
+ "name": "Absorption",
+ "displayName": "Absorption",
+ "type": "good"
+ },
+ {
+ "id": 23,
+ "name": "Saturation",
+ "displayName": "Saturation",
+ "type": "good"
+ }
+]
diff --git a/testagent/build.gradle.kts b/testagent/build.gradle.kts
index 3bd8c8c..73eb583 100644
--- a/testagent/build.gradle.kts
+++ b/testagent/build.gradle.kts
@@ -1,6 +1,6 @@
plugins {
java
- alias(libs.plugins.shadow)
+ id("com.gradleup.shadow")
}
dependencies {
implementation(libs.asm)