Make pickaxe ability display use AbilityUtils
[no changelog]
This commit is contained in:
@@ -41,3 +41,9 @@ SPDX-FileCopyrightText = ["Linnea Gräf <nea@nea.moe>", "Firmament Contributors"
|
|||||||
path = ["**/META-INF/services/*"]
|
path = ["**/META-INF/services/*"]
|
||||||
SPDX-License-Identifier = "CC0-1.0"
|
SPDX-License-Identifier = "CC0-1.0"
|
||||||
SPDX-FileCopyrightText = ["Linnea Gräf <nea@nea.moe>", "Firmament Contributors"]
|
SPDX-FileCopyrightText = ["Linnea Gräf <nea@nea.moe>", "Firmament Contributors"]
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = ["src/test/resources/testdata/**/*.snbt"]
|
||||||
|
SPDX-License-Identifier = "CC-BY-4.0"
|
||||||
|
SPDX-FileCopyrightText = ["Linnea Gräf <nea@nea.moe>", "Firmament Contributors"]
|
||||||
|
|
||||||
|
|||||||
532
build.gradle.kts
532
build.gradle.kts
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import com.google.devtools.ksp.gradle.KspTaskJvm
|
import com.google.devtools.ksp.gradle.KspTaskJvm
|
||||||
|
import com.google.gson.JsonArray
|
||||||
import moe.nea.licenseextractificator.LicenseDiscoveryTask
|
import moe.nea.licenseextractificator.LicenseDiscoveryTask
|
||||||
import net.fabricmc.loom.LoomGradleExtension
|
import net.fabricmc.loom.LoomGradleExtension
|
||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
@@ -14,353 +15,356 @@ import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
alias(libs.plugins.kotlin.jvm)
|
alias(libs.plugins.kotlin.jvm)
|
||||||
alias(libs.plugins.kotlin.plugin.serialization)
|
alias(libs.plugins.kotlin.plugin.serialization)
|
||||||
alias(libs.plugins.kotlin.plugin.powerassert)
|
alias(libs.plugins.kotlin.plugin.powerassert)
|
||||||
alias(libs.plugins.kotlin.plugin.ksp)
|
alias(libs.plugins.kotlin.plugin.ksp)
|
||||||
alias(libs.plugins.loom)
|
alias(libs.plugins.loom)
|
||||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||||
id("moe.nea.licenseextractificator")
|
id("moe.nea.licenseextractificator")
|
||||||
}
|
}
|
||||||
|
|
||||||
version = getGitTagInfo()
|
version = getGitTagInfo()
|
||||||
group = rootProject.property("maven_group").toString()
|
group = rootProject.property("maven_group").toString()
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion.set(JavaLanguageVersion.of(21))
|
languageVersion.set(JavaLanguageVersion.of(21))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tasks.withType(KotlinCompile::class) {
|
tasks.withType(KotlinCompile::class) {
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
jvmTarget.set(JvmTarget.JVM_21)
|
jvmTarget.set(JvmTarget.JVM_21)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven("https://maven.terraformersmc.com/releases/")
|
maven("https://maven.terraformersmc.com/releases/")
|
||||||
maven("https://maven.shedaniel.me")
|
maven("https://maven.shedaniel.me")
|
||||||
maven("https://maven.fabricmc.net")
|
maven("https://maven.fabricmc.net")
|
||||||
maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1")
|
maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1")
|
||||||
maven("https://api.modrinth.com/maven") {
|
maven("https://api.modrinth.com/maven") {
|
||||||
content {
|
content {
|
||||||
includeGroup("maven.modrinth")
|
includeGroup("maven.modrinth")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maven("https://repo.sleeping.town") {
|
maven("https://repo.sleeping.town") {
|
||||||
content {
|
content {
|
||||||
includeGroup("com.unascribed")
|
includeGroup("com.unascribed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ivy("https://github.com/HotswapProjects/HotswapAgent/releases/download") {
|
ivy("https://github.com/HotswapProjects/HotswapAgent/releases/download") {
|
||||||
patternLayout {
|
patternLayout {
|
||||||
artifact("[revision]/[artifact]-[revision].[ext]")
|
artifact("[revision]/[artifact]-[revision].[ext]")
|
||||||
}
|
}
|
||||||
content {
|
content {
|
||||||
includeGroup("virtual.github.hotswapagent")
|
includeGroup("virtual.github.hotswapagent")
|
||||||
}
|
}
|
||||||
metadataSources {
|
metadataSources {
|
||||||
artifact()
|
artifact()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maven("https://server.bbkr.space/artifactory/libs-release")
|
maven("https://server.bbkr.space/artifactory/libs-release")
|
||||||
maven("https://repo.nea.moe/releases")
|
maven("https://repo.nea.moe/releases")
|
||||||
maven("https://maven.notenoughupdates.org/releases")
|
maven("https://maven.notenoughupdates.org/releases")
|
||||||
maven("https://repo.nea.moe/mirror")
|
maven("https://repo.nea.moe/mirror")
|
||||||
maven("https://jitpack.io/") {
|
maven("https://jitpack.io/") {
|
||||||
content {
|
content {
|
||||||
includeGroupByRegex("(com|io)\\.github\\..+")
|
includeGroupByRegex("(com|io)\\.github\\..+")
|
||||||
excludeModule("io.github.cottonmc", "LibGui")
|
excludeModule("io.github.cottonmc", "LibGui")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maven("https://repo.hypixel.net/repository/Hypixel/")
|
maven("https://repo.hypixel.net/repository/Hypixel/")
|
||||||
maven("https://maven.azureaaron.net/snapshots")
|
maven("https://maven.azureaaron.net/snapshots")
|
||||||
maven("https://maven.azureaaron.net/releases")
|
maven("https://maven.azureaaron.net/releases")
|
||||||
maven("https://www.cursemaven.com")
|
maven("https://www.cursemaven.com")
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kotlin {
|
kotlin {
|
||||||
sourceSets.all {
|
sourceSets.all {
|
||||||
languageSettings {
|
languageSettings {
|
||||||
enableLanguageFeature("BreakContinueInInlineLambdas")
|
enableLanguageFeature("BreakContinueInInlineLambdas")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun String.capitalizeN() = replaceFirstChar { it.uppercaseChar() }
|
fun String.capitalizeN() = replaceFirstChar { it.uppercaseChar() }
|
||||||
fun innerJarsOf(name: String, dependency: Dependency): FileCollection {
|
fun innerJarsOf(name: String, dependency: Dependency): FileCollection {
|
||||||
val task = tasks.create("unpackInnerJarsFor${name.capitalizeN()}", InnerJarsUnpacker::class) {
|
val task = tasks.create("unpackInnerJarsFor${name.capitalizeN()}", InnerJarsUnpacker::class) {
|
||||||
this.inputJars.setFrom(files(configurations.detachedConfiguration(dependency)))
|
this.inputJars.setFrom(files(configurations.detachedConfiguration(dependency)))
|
||||||
this.outputDir.set(layout.buildDirectory.dir("unpackedJars/$name").also {
|
this.outputDir.set(layout.buildDirectory.dir("unpackedJars/$name").also {
|
||||||
it.get().asFile.mkdirs()
|
it.get().asFile.mkdirs()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
println("Constructed innerJars task: ${project.files(task).toList()}")
|
println("Constructed innerJars task: ${project.files(task).toList()}")
|
||||||
return project.files(task)
|
return project.files(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
val compatSourceSets: MutableSet<SourceSet> = mutableSetOf()
|
val compatSourceSets: MutableSet<SourceSet> = mutableSetOf()
|
||||||
fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): SourceSet {
|
fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): SourceSet {
|
||||||
val ss = sourceSets.create(name) {
|
val ss = sourceSets.create(name) {
|
||||||
this.java.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java")))
|
this.java.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java")))
|
||||||
this.kotlin.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java")))
|
this.kotlin.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java")))
|
||||||
}
|
}
|
||||||
compatSourceSets.add(ss)
|
compatSourceSets.add(ss)
|
||||||
loom.createRemapConfigurations(ss)
|
loom.createRemapConfigurations(ss)
|
||||||
val mainSS = sourceSets.main.get()
|
val mainSS = sourceSets.main.get()
|
||||||
val upperName = ss.name.capitalizeN()
|
val upperName = ss.name.capitalizeN()
|
||||||
configurations {
|
configurations {
|
||||||
(ss.implementationConfigurationName) {
|
(ss.implementationConfigurationName) {
|
||||||
extendsFrom(getByName(mainSS.compileClasspathConfigurationName))
|
extendsFrom(getByName(mainSS.compileClasspathConfigurationName))
|
||||||
}
|
}
|
||||||
(ss.annotationProcessorConfigurationName) {
|
(ss.annotationProcessorConfigurationName) {
|
||||||
extendsFrom(getByName(mainSS.annotationProcessorConfigurationName))
|
extendsFrom(getByName(mainSS.annotationProcessorConfigurationName))
|
||||||
}
|
}
|
||||||
(mainSS.runtimeOnlyConfigurationName) {
|
(mainSS.runtimeOnlyConfigurationName) {
|
||||||
extendsFrom(getByName(ss.runtimeClasspathConfigurationName))
|
extendsFrom(getByName(ss.runtimeClasspathConfigurationName))
|
||||||
}
|
}
|
||||||
("ksp$upperName") {
|
("ksp$upperName") {
|
||||||
extendsFrom(ksp.get())
|
extendsFrom(ksp.get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
tasks.named("ksp${upperName}Kotlin", KspTaskJvm::class) {
|
tasks.named("ksp${upperName}Kotlin", KspTaskJvm::class) {
|
||||||
this.options.add(SubpluginOption("apoption", "firmament.sourceset=${ss.name}"))
|
this.options.add(SubpluginOption("apoption", "firmament.sourceset=${ss.name}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
runtimeOnly(ss.output)
|
runtimeOnly(ss.output)
|
||||||
(ss.implementationConfigurationName)(sourceSets.main.get().output)
|
(ss.implementationConfigurationName)(sourceSets.main.get().output)
|
||||||
}
|
}
|
||||||
tasks.shadowJar {
|
tasks.shadowJar {
|
||||||
from(ss.output)
|
from(ss.output)
|
||||||
}
|
}
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
|
|
||||||
val SourceSet.modImplementationConfigurationName
|
val SourceSet.modImplementationConfigurationName
|
||||||
get() =
|
get() =
|
||||||
loom.remapConfigurations.find {
|
loom.remapConfigurations.find {
|
||||||
it.targetConfigurationName.get() == this.implementationConfigurationName
|
it.targetConfigurationName.get() == this.implementationConfigurationName
|
||||||
}!!.sourceConfiguration
|
}!!.sourceConfiguration
|
||||||
val configuredSourceSet = createIsolatedSourceSet("configured")
|
val configuredSourceSet = createIsolatedSourceSet("configured")
|
||||||
val sodiumSourceSet = createIsolatedSourceSet("sodium")
|
val sodiumSourceSet = createIsolatedSourceSet("sodium")
|
||||||
val citResewnSourceSet = createIsolatedSourceSet("citresewn")
|
val citResewnSourceSet = createIsolatedSourceSet("citresewn")
|
||||||
|
|
||||||
val shadowMe by configurations.creating {
|
val shadowMe by configurations.creating {
|
||||||
exclude(group = "org.jetbrains.kotlin")
|
exclude(group = "org.jetbrains.kotlin")
|
||||||
exclude(group = "org.jetbrains.kotlinx")
|
exclude(group = "org.jetbrains.kotlinx")
|
||||||
exclude(group = "org.jetbrains")
|
exclude(group = "org.jetbrains")
|
||||||
exclude(module = "gson")
|
exclude(module = "gson")
|
||||||
exclude(group = "org.slf4j")
|
exclude(group = "org.slf4j")
|
||||||
}
|
}
|
||||||
val transInclude by configurations.creating {
|
val transInclude by configurations.creating {
|
||||||
exclude(group = "com.mojang")
|
exclude(group = "com.mojang")
|
||||||
exclude(group = "org.jetbrains.kotlin")
|
exclude(group = "org.jetbrains.kotlin")
|
||||||
exclude(group = "org.jetbrains.kotlinx")
|
exclude(group = "org.jetbrains.kotlinx")
|
||||||
isTransitive = true
|
isTransitive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val hotswap by configurations.creating {
|
val hotswap by configurations.creating {
|
||||||
isVisible = false
|
isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
val nonModImplentation by configurations.creating {
|
val nonModImplentation by configurations.creating {
|
||||||
configurations.implementation.get().extendsFrom(this)
|
configurations.implementation.get().extendsFrom(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Minecraft dependencies
|
// Minecraft dependencies
|
||||||
"minecraft"(libs.minecraft)
|
"minecraft"(libs.minecraft)
|
||||||
"mappings"("net.fabricmc:yarn:${libs.versions.yarn.get()}:v2")
|
"mappings"("net.fabricmc:yarn:${libs.versions.yarn.get()}:v2")
|
||||||
|
|
||||||
// Hotswap Dependency
|
// Hotswap Dependency
|
||||||
hotswap(libs.hotswap)
|
hotswap(libs.hotswap)
|
||||||
|
|
||||||
// Fabric dependencies
|
// Fabric dependencies
|
||||||
modImplementation(libs.fabric.loader)
|
modImplementation(libs.fabric.loader)
|
||||||
modImplementation(libs.fabric.kotlin)
|
modImplementation(libs.fabric.kotlin)
|
||||||
modImplementation(libs.modmenu)
|
modImplementation(libs.modmenu)
|
||||||
modImplementation(libs.moulconfig)
|
modImplementation(libs.moulconfig)
|
||||||
modImplementation(libs.manninghamMills)
|
modImplementation(libs.manninghamMills)
|
||||||
modCompileOnly(libs.explosiveenhancement)
|
modCompileOnly(libs.explosiveenhancement)
|
||||||
modImplementation(libs.hypixelmodapi)
|
modImplementation(libs.hypixelmodapi)
|
||||||
include(libs.hypixelmodapi.fabric)
|
include(libs.hypixelmodapi.fabric)
|
||||||
compileOnly(project(":javaplugin"))
|
compileOnly(project(":javaplugin"))
|
||||||
annotationProcessor(project(":javaplugin"))
|
annotationProcessor(project(":javaplugin"))
|
||||||
implementation("com.google.auto.service:auto-service-annotations:1.1.1")
|
implementation("com.google.auto.service:auto-service-annotations:1.1.1")
|
||||||
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.2.0")
|
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.2.0")
|
||||||
include(libs.manninghamMills)
|
include(libs.manninghamMills)
|
||||||
include(libs.moulconfig)
|
include(libs.moulconfig)
|
||||||
|
|
||||||
|
|
||||||
annotationProcessor(libs.mixinextras)
|
annotationProcessor(libs.mixinextras)
|
||||||
implementation(libs.mixinextras)
|
implementation(libs.mixinextras)
|
||||||
include(libs.mixinextras)
|
include(libs.mixinextras)
|
||||||
|
|
||||||
nonModImplentation(libs.nealisp)
|
nonModImplentation(libs.nealisp)
|
||||||
shadowMe(libs.nealisp)
|
shadowMe(libs.nealisp)
|
||||||
|
|
||||||
modCompileOnly(libs.fabric.api)
|
modCompileOnly(libs.fabric.api)
|
||||||
modRuntimeOnly(libs.fabric.api.deprecated)
|
modRuntimeOnly(libs.fabric.api.deprecated)
|
||||||
modApi(libs.architectury)
|
modApi(libs.architectury)
|
||||||
modCompileOnly(libs.jarvis.api)
|
modCompileOnly(libs.jarvis.api)
|
||||||
include(libs.jarvis.fabric)
|
include(libs.jarvis.fabric)
|
||||||
|
|
||||||
modCompileOnly(libs.femalegender)
|
modCompileOnly(libs.femalegender)
|
||||||
(configuredSourceSet.modImplementationConfigurationName)(libs.configured)
|
(configuredSourceSet.modImplementationConfigurationName)(libs.configured)
|
||||||
(sodiumSourceSet.modImplementationConfigurationName)(libs.sodium)
|
(sodiumSourceSet.modImplementationConfigurationName)(libs.sodium)
|
||||||
|
|
||||||
(citResewnSourceSet.modImplementationConfigurationName)(
|
(citResewnSourceSet.modImplementationConfigurationName)(
|
||||||
innerJarsOf("citresewn", dependencies.create(libs.citresewn.get())).asFileTree)
|
innerJarsOf("citresewn", dependencies.create(libs.citresewn.get())).asFileTree)
|
||||||
(citResewnSourceSet.modImplementationConfigurationName)(libs.citresewn)
|
(citResewnSourceSet.modImplementationConfigurationName)(libs.citresewn)
|
||||||
|
|
||||||
// Actual dependencies
|
// Actual dependencies
|
||||||
modCompileOnly(libs.rei.api) {
|
modCompileOnly(libs.rei.api) {
|
||||||
exclude(module = "architectury")
|
exclude(module = "architectury")
|
||||||
exclude(module = "architectury-fabric")
|
exclude(module = "architectury-fabric")
|
||||||
}
|
}
|
||||||
nonModImplentation(libs.repoparser)
|
nonModImplentation(libs.repoparser)
|
||||||
shadowMe(libs.repoparser)
|
shadowMe(libs.repoparser)
|
||||||
fun ktor(mod: String) = "io.ktor:ktor-$mod-jvm:${libs.versions.ktor.get()}"
|
fun ktor(mod: String) = "io.ktor:ktor-$mod-jvm:${libs.versions.ktor.get()}"
|
||||||
modCompileOnly(libs.citresewn)
|
modCompileOnly(libs.citresewn)
|
||||||
transInclude(nonModImplentation(ktor("client-core"))!!)
|
transInclude(nonModImplentation(ktor("client-core"))!!)
|
||||||
transInclude(nonModImplentation(ktor("client-java"))!!)
|
transInclude(nonModImplentation(ktor("client-java"))!!)
|
||||||
transInclude(nonModImplentation(ktor("serialization-kotlinx-json"))!!)
|
transInclude(nonModImplentation(ktor("serialization-kotlinx-json"))!!)
|
||||||
transInclude(nonModImplentation(ktor("client-content-negotiation"))!!)
|
transInclude(nonModImplentation(ktor("client-content-negotiation"))!!)
|
||||||
transInclude(nonModImplentation(ktor("client-encoding"))!!)
|
transInclude(nonModImplentation(ktor("client-encoding"))!!)
|
||||||
transInclude(nonModImplentation(ktor("client-logging"))!!)
|
transInclude(nonModImplentation(ktor("client-logging"))!!)
|
||||||
|
|
||||||
// Dev environment preinstalled mods
|
// Dev environment preinstalled mods
|
||||||
modLocalRuntime(libs.bundles.runtime.required)
|
modLocalRuntime(libs.bundles.runtime.required)
|
||||||
modLocalRuntime(libs.bundles.runtime.optional)
|
modLocalRuntime(libs.bundles.runtime.optional)
|
||||||
modLocalRuntime(libs.jarvis.fabric)
|
modLocalRuntime(libs.jarvis.fabric)
|
||||||
|
|
||||||
transInclude.resolvedConfiguration.resolvedArtifacts.forEach {
|
transInclude.resolvedConfiguration.resolvedArtifacts.forEach {
|
||||||
include(it.moduleVersion.id.toString())
|
include(it.moduleVersion.id.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
|
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
|
||||||
|
|
||||||
implementation(project(":symbols"))
|
implementation(project(":symbols"))
|
||||||
ksp(project(":symbols"))
|
ksp(project(":symbols"))
|
||||||
}
|
|
||||||
|
|
||||||
tasks.test {
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loom {
|
loom {
|
||||||
clientOnlyMinecraftJar()
|
clientOnlyMinecraftJar()
|
||||||
accessWidenerPath.set(project.file("src/main/resources/firmament.accesswidener"))
|
accessWidenerPath.set(project.file("src/main/resources/firmament.accesswidener"))
|
||||||
runs {
|
runs {
|
||||||
removeIf { it.name != "client" }
|
removeIf { it.name != "client" }
|
||||||
named("client") {
|
configureEach {
|
||||||
property("devauth.enabled", "true")
|
property("fabric.log.level", "info")
|
||||||
property("fabric.log.level", "info")
|
property("firmament.debug", "true")
|
||||||
property("firmament.debug", "true")
|
property("firmament.classroots",
|
||||||
property("firmament.classroots",
|
compatSourceSets.joinToString(File.pathSeparator) {
|
||||||
compatSourceSets.joinToString(File.pathSeparator) {
|
File(it.output.classesDirs.asPath).absolutePath
|
||||||
File(it.output.classesDirs.asPath).absolutePath
|
})
|
||||||
})
|
property("mixin.debug", "true")
|
||||||
property("mixin.debug", "true")
|
|
||||||
|
|
||||||
parseEnvFile(file(".env")).forEach { (t, u) ->
|
parseEnvFile(file(".env")).forEach { (t, u) ->
|
||||||
environmentVariable(t, u)
|
environmentVariable(t, u)
|
||||||
}
|
}
|
||||||
parseEnvFile(file(".properties")).forEach { (t, u) ->
|
parseEnvFile(file(".properties")).forEach { (t, u) ->
|
||||||
property(t, u)
|
property(t, u)
|
||||||
}
|
}
|
||||||
vmArg("-ea")
|
}
|
||||||
vmArg("-XX:+AllowEnhancedClassRedefinition")
|
named("client") {
|
||||||
vmArg("-XX:HotswapAgent=external")
|
property("devauth.enabled", "true")
|
||||||
vmArg("-javaagent:${hotswap.resolve().single().absolutePath}")
|
vmArg("-ea")
|
||||||
}
|
vmArg("-XX:+AllowEnhancedClassRedefinition")
|
||||||
}
|
vmArg("-XX:HotswapAgent=external")
|
||||||
|
vmArg("-javaagent:${hotswap.resolve().single().absolutePath}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
tasks.withType<JavaCompile> {
|
tasks.withType<JavaCompile> {
|
||||||
this.sourceCompatibility = "21"
|
this.sourceCompatibility = "21"
|
||||||
this.targetCompatibility = "21"
|
this.targetCompatibility = "21"
|
||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
val module = "ALL-UNNAMED"
|
val module = "ALL-UNNAMED"
|
||||||
options.forkOptions.jvmArgs!!.addAll(listOf(
|
options.forkOptions.jvmArgs!!.addAll(listOf(
|
||||||
"--add-exports=jdk.compiler/com.sun.tools.javac.util=$module",
|
"--add-exports=jdk.compiler/com.sun.tools.javac.util=$module",
|
||||||
"--add-exports=jdk.compiler/com.sun.tools.javac.comp=$module",
|
"--add-exports=jdk.compiler/com.sun.tools.javac.comp=$module",
|
||||||
"--add-exports=jdk.compiler/com.sun.tools.javac.tree=$module",
|
"--add-exports=jdk.compiler/com.sun.tools.javac.tree=$module",
|
||||||
"--add-exports=jdk.compiler/com.sun.tools.javac.api=$module",
|
"--add-exports=jdk.compiler/com.sun.tools.javac.api=$module",
|
||||||
"--add-exports=jdk.compiler/com.sun.tools.javac.code=$module",
|
"--add-exports=jdk.compiler/com.sun.tools.javac.code=$module",
|
||||||
))
|
))
|
||||||
options.isFork = true
|
options.isFork = true
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
options.compilerArgs.add("-Xplugin:IntermediaryNameReplacement mappingFile=${LoomGradleExtension.get(project).mappingsFile.absolutePath} sourceNs=named")
|
options.compilerArgs.add("-Xplugin:IntermediaryNameReplacement mappingFile=${LoomGradleExtension.get(project).mappingsFile.absolutePath} sourceNs=named")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.jar {
|
tasks.jar {
|
||||||
destinationDirectory.set(layout.buildDirectory.dir("badjars"))
|
destinationDirectory.set(layout.buildDirectory.dir("badjars"))
|
||||||
archiveClassifier.set("slim")
|
archiveClassifier.set("slim")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.shadowJar {
|
tasks.shadowJar {
|
||||||
configurations = listOf(shadowMe)
|
configurations = listOf(shadowMe)
|
||||||
archiveClassifier.set("dev")
|
archiveClassifier.set("dev")
|
||||||
relocate("io.github.moulberry.repo", "moe.nea.firmament.deps.repo")
|
relocate("io.github.moulberry.repo", "moe.nea.firmament.deps.repo")
|
||||||
destinationDirectory.set(layout.buildDirectory.dir("badjars"))
|
destinationDirectory.set(layout.buildDirectory.dir("badjars"))
|
||||||
mergeServiceFiles()
|
mergeServiceFiles()
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.remapJar {
|
tasks.remapJar {
|
||||||
injectAccessWidener.set(true)
|
injectAccessWidener.set(true)
|
||||||
inputFile.set(tasks.shadowJar.flatMap { it.archiveFile })
|
inputFile.set(tasks.shadowJar.flatMap { it.archiveFile })
|
||||||
dependsOn(tasks.shadowJar)
|
dependsOn(tasks.shadowJar)
|
||||||
archiveClassifier.set("")
|
archiveClassifier.set("")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.processResources {
|
tasks.processResources {
|
||||||
val replacements = listOf(
|
val replacements = listOf(
|
||||||
"version" to project.version.toString(),
|
"version" to project.version.toString(),
|
||||||
"minecraft_version" to libs.versions.minecraft.get(),
|
"minecraft_version" to libs.versions.minecraft.get(),
|
||||||
"fabric_kotlin_version" to libs.versions.fabric.kotlin.get(),
|
"fabric_kotlin_version" to libs.versions.fabric.kotlin.get(),
|
||||||
"rei_version" to libs.versions.rei.get()
|
"rei_version" to libs.versions.rei.get()
|
||||||
)
|
)
|
||||||
replacements.forEach { (key, value) -> inputs.property(key, value) }
|
replacements.forEach { (key, value) -> inputs.property(key, value) }
|
||||||
filesMatching("**/fabric.mod.json") {
|
filesMatching("**/fabric.mod.json") {
|
||||||
expand(*replacements.toTypedArray())
|
expand(*replacements.toTypedArray())
|
||||||
}
|
}
|
||||||
exclude("**/*.license")
|
exclude("**/*.license")
|
||||||
from(tasks.scanLicenses)
|
from(tasks.scanLicenses)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.scanLicenses {
|
tasks.scanLicenses {
|
||||||
scanConfiguration(nonModImplentation)
|
scanConfiguration(nonModImplentation)
|
||||||
scanConfiguration(configurations.modCompileClasspath.get())
|
scanConfiguration(configurations.modCompileClasspath.get())
|
||||||
outputFile.set(layout.buildDirectory.file("LICENSES-FIRMAMENT.json"))
|
outputFile.set(layout.buildDirectory.file("LICENSES-FIRMAMENT.json"))
|
||||||
licenseFormatter.set(moe.nea.licenseextractificator.JsonLicenseFormatter())
|
licenseFormatter.set(moe.nea.licenseextractificator.JsonLicenseFormatter())
|
||||||
}
|
}
|
||||||
tasks.create("printAllLicenses", LicenseDiscoveryTask::class.java, licensing).apply {
|
tasks.create("printAllLicenses", LicenseDiscoveryTask::class.java, licensing).apply {
|
||||||
outputFile.set(layout.buildDirectory.file("LICENSES-FIRMAMENT.txt"))
|
outputFile.set(layout.buildDirectory.file("LICENSES-FIRMAMENT.txt"))
|
||||||
licenseFormatter.set(moe.nea.licenseextractificator.TextLicenseFormatter())
|
licenseFormatter.set(moe.nea.licenseextractificator.TextLicenseFormatter())
|
||||||
scanConfiguration(nonModImplentation)
|
scanConfiguration(nonModImplentation)
|
||||||
scanConfiguration(configurations.modCompileClasspath.get())
|
scanConfiguration(configurations.modCompileClasspath.get())
|
||||||
doLast {
|
doLast {
|
||||||
println(outputFile.get().asFile.readText())
|
println(outputFile.get().asFile.readText())
|
||||||
}
|
}
|
||||||
outputs.upToDateWhen { false }
|
outputs.upToDateWhen { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<AbstractArchiveTask>().configureEach {
|
tasks.withType<AbstractArchiveTask>().configureEach {
|
||||||
isPreserveFileTimestamps = false
|
isPreserveFileTimestamps = false
|
||||||
isReproducibleFileOrder = true
|
isReproducibleFileOrder = true
|
||||||
}
|
}
|
||||||
|
|
||||||
licensing.addExtraLicenseMatchers()
|
licensing.addExtraLicenseMatchers()
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
package moe.nea.firmament
|
package moe.nea.firmament
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher
|
import com.mojang.brigadier.CommandDispatcher
|
||||||
@@ -33,7 +31,6 @@ import kotlinx.coroutines.plus
|
|||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
import kotlinx.serialization.json.decodeFromStream
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
import net.minecraft.client.render.chunk.SectionBuilder
|
|
||||||
import net.minecraft.command.CommandRegistryAccess
|
import net.minecraft.command.CommandRegistryAccess
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import moe.nea.firmament.commands.registerFirmamentCommand
|
import moe.nea.firmament.commands.registerFirmamentCommand
|
||||||
@@ -51,98 +48,98 @@ import moe.nea.firmament.util.SBData
|
|||||||
import moe.nea.firmament.util.data.IDataHolder
|
import moe.nea.firmament.util.data.IDataHolder
|
||||||
|
|
||||||
object Firmament {
|
object Firmament {
|
||||||
const val MOD_ID = "firmament"
|
const val MOD_ID = "firmament"
|
||||||
|
|
||||||
val DEBUG = System.getProperty("firmament.debug") == "true"
|
val DEBUG = System.getProperty("firmament.debug") == "true"
|
||||||
val DATA_DIR: Path = Path.of(".firmament").also { Files.createDirectories(it) }
|
val DATA_DIR: Path = Path.of(".firmament").also { Files.createDirectories(it) }
|
||||||
val CONFIG_DIR: Path = Path.of("config/firmament").also { Files.createDirectories(it) }
|
val CONFIG_DIR: Path = Path.of("config/firmament").also { Files.createDirectories(it) }
|
||||||
val logger: Logger = LogManager.getLogger("Firmament")
|
val logger: Logger = LogManager.getLogger("Firmament")
|
||||||
private val metadata: ModMetadata by lazy {
|
private val metadata: ModMetadata by lazy {
|
||||||
FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().metadata
|
FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().metadata
|
||||||
}
|
}
|
||||||
val version: Version by lazy { metadata.version }
|
val version: Version by lazy { metadata.version }
|
||||||
|
|
||||||
val json = Json {
|
val json = Json {
|
||||||
prettyPrint = DEBUG
|
prettyPrint = DEBUG
|
||||||
isLenient = true
|
isLenient = true
|
||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
encodeDefaults = true
|
encodeDefaults = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val httpClient by lazy {
|
val httpClient by lazy {
|
||||||
HttpClient {
|
HttpClient {
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json(json)
|
json(json)
|
||||||
}
|
}
|
||||||
install(ContentEncoding) {
|
install(ContentEncoding) {
|
||||||
gzip()
|
gzip()
|
||||||
deflate()
|
deflate()
|
||||||
}
|
}
|
||||||
install(UserAgent) {
|
install(UserAgent) {
|
||||||
agent = "Firmament/$version"
|
agent = "Firmament/$version"
|
||||||
}
|
}
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
install(Logging) {
|
install(Logging) {
|
||||||
level = LogLevel.INFO
|
level = LogLevel.INFO
|
||||||
}
|
}
|
||||||
install(HttpCache)
|
install(HttpCache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val globalJob = Job()
|
val globalJob = Job()
|
||||||
val coroutineScope =
|
val coroutineScope =
|
||||||
CoroutineScope(EmptyCoroutineContext + CoroutineName("Firmament")) + SupervisorJob(globalJob)
|
CoroutineScope(EmptyCoroutineContext + CoroutineName("Firmament")) + SupervisorJob(globalJob)
|
||||||
|
|
||||||
private fun registerCommands(
|
private fun registerCommands(
|
||||||
dispatcher: CommandDispatcher<FabricClientCommandSource>,
|
dispatcher: CommandDispatcher<FabricClientCommandSource>,
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
ctx: CommandRegistryAccess
|
ctx: CommandRegistryAccess
|
||||||
) {
|
) {
|
||||||
registerFirmamentCommand(dispatcher)
|
registerFirmamentCommand(dispatcher)
|
||||||
CommandEvent.publish(CommandEvent(dispatcher, ctx, MC.networkHandler?.commandDispatcher))
|
CommandEvent.publish(CommandEvent(dispatcher, ctx, MC.networkHandler?.commandDispatcher))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun onInitialize() {
|
fun onInitialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun onClientInitialize() {
|
fun onClientInitialize() {
|
||||||
FeatureManager.subscribeEvents()
|
FeatureManager.subscribeEvents()
|
||||||
var tick = 0
|
var tick = 0
|
||||||
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance ->
|
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance ->
|
||||||
TickEvent.publish(TickEvent(tick++))
|
TickEvent.publish(TickEvent(tick++))
|
||||||
})
|
})
|
||||||
IDataHolder.registerEvents()
|
IDataHolder.registerEvents()
|
||||||
RepoManager.initialize()
|
RepoManager.initialize()
|
||||||
SBData.init()
|
SBData.init()
|
||||||
FeatureManager.autoload()
|
FeatureManager.autoload()
|
||||||
HypixelStaticData.spawnDataCollectionLoop()
|
HypixelStaticData.spawnDataCollectionLoop()
|
||||||
ClientCommandRegistrationCallback.EVENT.register(this::registerCommands)
|
ClientCommandRegistrationCallback.EVENT.register(this::registerCommands)
|
||||||
ClientLifecycleEvents.CLIENT_STARTED.register(ClientLifecycleEvents.ClientStarted {
|
ClientLifecycleEvents.CLIENT_STARTED.register(ClientLifecycleEvents.ClientStarted {
|
||||||
ClientStartedEvent.publish(ClientStartedEvent())
|
ClientStartedEvent.publish(ClientStartedEvent())
|
||||||
})
|
})
|
||||||
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
|
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
|
||||||
logger.info("Shutting down Firmament coroutines")
|
logger.info("Shutting down Firmament coroutines")
|
||||||
globalJob.cancel()
|
globalJob.cancel()
|
||||||
})
|
})
|
||||||
registerFirmamentEvents()
|
registerFirmamentEvents()
|
||||||
ItemTooltipCallback.EVENT.register { stack, context, type, lines ->
|
ItemTooltipCallback.EVENT.register { stack, context, type, lines ->
|
||||||
ItemTooltipEvent.publish(ItemTooltipEvent(stack, context, type, lines))
|
ItemTooltipEvent.publish(ItemTooltipEvent(stack, context, type, lines))
|
||||||
}
|
}
|
||||||
ScreenEvents.AFTER_INIT.register(ScreenEvents.AfterInit { client, screen, scaledWidth, scaledHeight ->
|
ScreenEvents.AFTER_INIT.register(ScreenEvents.AfterInit { client, screen, scaledWidth, scaledHeight ->
|
||||||
ScreenEvents.afterRender(screen)
|
ScreenEvents.afterRender(screen)
|
||||||
.register(ScreenEvents.AfterRender { screen, drawContext, mouseX, mouseY, tickDelta ->
|
.register(ScreenEvents.AfterRender { screen, drawContext, mouseX, mouseY, tickDelta ->
|
||||||
ScreenRenderPostEvent.publish(ScreenRenderPostEvent(screen, mouseX, mouseY, tickDelta, drawContext))
|
ScreenRenderPostEvent.publish(ScreenRenderPostEvent(screen, mouseX, mouseY, tickDelta, drawContext))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun identifier(path: String) = Identifier.of(MOD_ID, path)
|
fun identifier(path: String) = Identifier.of(MOD_ID, path)
|
||||||
inline fun <reified T : Any> tryDecodeJsonFromStream(inputStream: InputStream): Result<T> {
|
inline fun <reified T : Any> tryDecodeJsonFromStream(inputStream: InputStream): Result<T> {
|
||||||
return runCatching {
|
return runCatching {
|
||||||
json.decodeFromStream<T>(inputStream)
|
json.decodeFromStream<T>(inputStream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ package moe.nea.firmament.events
|
|||||||
|
|
||||||
import net.minecraft.client.gui.DrawContext
|
import net.minecraft.client.gui.DrawContext
|
||||||
import net.minecraft.client.render.RenderTickCounter
|
import net.minecraft.client.render.RenderTickCounter
|
||||||
|
import net.minecraft.world.GameMode
|
||||||
|
import moe.nea.firmament.util.MC
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when hud elements should be rendered, before the screen, but after the world.
|
* Called when hud elements should be rendered, before the screen, but after the world.
|
||||||
*/
|
*/
|
||||||
data class HudRenderEvent(val context: DrawContext, val tickDelta: RenderTickCounter) : FirmamentEvent() {
|
data class HudRenderEvent(val context: DrawContext, val tickDelta: RenderTickCounter) : FirmamentEvent() {
|
||||||
|
val isRenderingHud = !MC.options.hudHidden
|
||||||
|
val isRenderingCursor = MC.interactionManager?.currentGameMode != GameMode.SPECTATOR && isRenderingHud
|
||||||
companion object : FirmamentEventBus<HudRenderEvent>()
|
companion object : FirmamentEventBus<HudRenderEvent>()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
|
|||||||
import moe.nea.firmament.util.ClipboardUtils
|
import moe.nea.firmament.util.ClipboardUtils
|
||||||
import moe.nea.firmament.util.MC
|
import moe.nea.firmament.util.MC
|
||||||
import moe.nea.firmament.util.focusedItemStack
|
import moe.nea.firmament.util.focusedItemStack
|
||||||
|
import moe.nea.firmament.util.mc.SNbtFormatter.Companion.toPrettyString
|
||||||
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
|
||||||
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||||
import moe.nea.firmament.util.skyBlockId
|
import moe.nea.firmament.util.skyBlockId
|
||||||
@@ -44,6 +45,7 @@ object PowerUserTools : FirmamentFeature {
|
|||||||
val copyLoreData by keyBindingWithDefaultUnbound("copy-lore")
|
val copyLoreData by keyBindingWithDefaultUnbound("copy-lore")
|
||||||
val copySkullTexture by keyBindingWithDefaultUnbound("copy-skull-texture")
|
val copySkullTexture by keyBindingWithDefaultUnbound("copy-skull-texture")
|
||||||
val copyEntityData by keyBindingWithDefaultUnbound("entity-data")
|
val copyEntityData by keyBindingWithDefaultUnbound("entity-data")
|
||||||
|
val copyItemStack by keyBindingWithDefaultUnbound("copy-item-stack")
|
||||||
}
|
}
|
||||||
|
|
||||||
override val config
|
override val config
|
||||||
@@ -125,7 +127,7 @@ object PowerUserTools : FirmamentFeature {
|
|||||||
Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString()))
|
Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString()))
|
||||||
} else if (it.matches(TConfig.copyNbtData)) {
|
} else if (it.matches(TConfig.copyNbtData)) {
|
||||||
// TODO: copy full nbt
|
// TODO: copy full nbt
|
||||||
val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toString() ?: "<empty>"
|
val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toPrettyString() ?: "<empty>"
|
||||||
ClipboardUtils.setTextContent(nbt)
|
ClipboardUtils.setTextContent(nbt)
|
||||||
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt"))
|
lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt"))
|
||||||
} else if (it.matches(TConfig.copyLoreData)) {
|
} else if (it.matches(TConfig.copyLoreData)) {
|
||||||
@@ -157,6 +159,9 @@ object PowerUserTools : FirmamentFeature {
|
|||||||
Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString())
|
Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString())
|
||||||
)
|
)
|
||||||
println("Copied skull id: $skullTexture")
|
println("Copied skull id: $skullTexture")
|
||||||
|
} else if (it.matches(TConfig.copyItemStack)) {
|
||||||
|
ClipboardUtils.setTextContent(item.encode(MC.currentOrDefaultRegistries).toPrettyString())
|
||||||
|
lastCopiedStack = Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.stack"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.features.mining
|
package moe.nea.firmament.features.mining
|
||||||
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
@@ -30,155 +29,146 @@ import moe.nea.firmament.util.parseShortNumber
|
|||||||
import moe.nea.firmament.util.parseTimePattern
|
import moe.nea.firmament.util.parseTimePattern
|
||||||
import moe.nea.firmament.util.render.RenderCircleProgress
|
import moe.nea.firmament.util.render.RenderCircleProgress
|
||||||
import moe.nea.firmament.util.render.lerp
|
import moe.nea.firmament.util.render.lerp
|
||||||
|
import moe.nea.firmament.util.skyblock.AbilityUtils
|
||||||
import moe.nea.firmament.util.toShedaniel
|
import moe.nea.firmament.util.toShedaniel
|
||||||
import moe.nea.firmament.util.unformattedString
|
import moe.nea.firmament.util.unformattedString
|
||||||
import moe.nea.firmament.util.useMatch
|
import moe.nea.firmament.util.useMatch
|
||||||
|
|
||||||
object PickaxeAbility : FirmamentFeature {
|
object PickaxeAbility : FirmamentFeature {
|
||||||
override val identifier: String
|
override val identifier: String
|
||||||
get() = "pickaxe-info"
|
get() = "pickaxe-info"
|
||||||
|
|
||||||
|
|
||||||
object TConfig : ManagedConfig(identifier) {
|
object TConfig : ManagedConfig(identifier) {
|
||||||
val cooldownEnabled by toggle("ability-cooldown") { true }
|
val cooldownEnabled by toggle("ability-cooldown") { true }
|
||||||
val cooldownScale by integer("ability-scale", 16, 64) { 16 }
|
val cooldownScale by integer("ability-scale", 16, 64) { 16 }
|
||||||
val drillFuelBar by toggle("fuel-bar") { true }
|
val drillFuelBar by toggle("fuel-bar") { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
var lobbyJoinTime = TimeMark.farPast()
|
var lobbyJoinTime = TimeMark.farPast()
|
||||||
var lastUsage = mutableMapOf<String, TimeMark>()
|
var lastUsage = mutableMapOf<String, TimeMark>()
|
||||||
var abilityOverride: String? = null
|
var abilityOverride: String? = null
|
||||||
var defaultAbilityDurations = mutableMapOf<String, Duration>(
|
var defaultAbilityDurations = mutableMapOf<String, Duration>(
|
||||||
"Mining Speed Boost" to 120.seconds,
|
"Mining Speed Boost" to 120.seconds,
|
||||||
"Pickobulus" to 110.seconds,
|
"Pickobulus" to 110.seconds,
|
||||||
"Gemstone Infusion" to 140.seconds,
|
"Gemstone Infusion" to 140.seconds,
|
||||||
"Hazardous Miner" to 140.seconds,
|
"Hazardous Miner" to 140.seconds,
|
||||||
"Maniac Miner" to 59.seconds,
|
"Maniac Miner" to 59.seconds,
|
||||||
"Vein Seeker" to 60.seconds
|
"Vein Seeker" to 60.seconds
|
||||||
)
|
)
|
||||||
|
|
||||||
override val config: ManagedConfig
|
override val config: ManagedConfig
|
||||||
get() = TConfig
|
get() = TConfig
|
||||||
|
|
||||||
fun getCooldownPercentage(name: String, cooldown: Duration): Double {
|
fun getCooldownPercentage(name: String, cooldown: Duration): Double {
|
||||||
val sinceLastUsage = lastUsage[name]?.passedTime() ?: Duration.INFINITE
|
val sinceLastUsage = lastUsage[name]?.passedTime() ?: Duration.INFINITE
|
||||||
val sinceLobbyJoin = lobbyJoinTime.passedTime()
|
val sinceLobbyJoin = lobbyJoinTime.passedTime()
|
||||||
if (SBData.skyblockLocation == SkyBlockIsland.MINESHAFT) {
|
if (SBData.skyblockLocation == SkyBlockIsland.MINESHAFT) {
|
||||||
if (sinceLobbyJoin < sinceLastUsage) {
|
if (sinceLobbyJoin < sinceLastUsage) {
|
||||||
return 1.0
|
return 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sinceLastUsage < cooldown)
|
if (sinceLastUsage < cooldown)
|
||||||
return sinceLastUsage / cooldown
|
return sinceLastUsage / cooldown
|
||||||
return 1.0
|
return 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
fun onSlotClick(it: SlotClickEvent) {
|
fun onSlotClick(it: SlotClickEvent) {
|
||||||
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
|
if (MC.screen?.title?.unformattedString == "Heart of the Mountain") {
|
||||||
val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return
|
val name = it.stack.displayNameAccordingToNbt.unformattedString
|
||||||
val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull {
|
val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull {
|
||||||
cooldownPattern.useMatch(it.unformattedString) {
|
cooldownPattern.useMatch(it.unformattedString) {
|
||||||
parseTimePattern(group("cooldown"))
|
parseTimePattern(group("cooldown"))
|
||||||
}
|
}
|
||||||
} ?: return
|
} ?: return
|
||||||
defaultAbilityDurations[name] = cooldown
|
defaultAbilityDurations[name] = cooldown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
fun onDurabilityBar(it: DurabilityBarEvent) {
|
fun onDurabilityBar(it: DurabilityBarEvent) {
|
||||||
if (!TConfig.drillFuelBar) return
|
if (!TConfig.drillFuelBar) return
|
||||||
val lore = it.item.loreAccordingToNbt
|
val lore = it.item.loreAccordingToNbt
|
||||||
if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return
|
if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return
|
||||||
val maxFuel = lore.firstNotNullOfOrNull {
|
val maxFuel = lore.firstNotNullOfOrNull {
|
||||||
fuelPattern.useMatch(it.unformattedString) {
|
fuelPattern.useMatch(it.unformattedString) {
|
||||||
parseShortNumber(group("maxFuel"))
|
parseShortNumber(group("maxFuel"))
|
||||||
}
|
}
|
||||||
} ?: return
|
} ?: return
|
||||||
val extra = it.item.extraAttributes
|
val extra = it.item.extraAttributes
|
||||||
if (!extra.contains("drill_fuel")) return
|
if (!extra.contains("drill_fuel")) return
|
||||||
val fuel = extra.getInt("drill_fuel")
|
val fuel = extra.getInt("drill_fuel")
|
||||||
val percentage = fuel / maxFuel.toFloat()
|
val percentage = fuel / maxFuel.toFloat()
|
||||||
it.barOverride = DurabilityBarEvent.DurabilityBar(
|
it.barOverride = DurabilityBarEvent.DurabilityBar(
|
||||||
lerp(
|
lerp(
|
||||||
DyeColor.RED.toShedaniel(),
|
DyeColor.RED.toShedaniel(),
|
||||||
DyeColor.GREEN.toShedaniel(),
|
DyeColor.GREEN.toShedaniel(),
|
||||||
percentage
|
percentage
|
||||||
), percentage
|
), percentage
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
fun onChatMessage(it: ProcessChatEvent) {
|
fun onChatMessage(it: ProcessChatEvent) {
|
||||||
abilityUsePattern.useMatch(it.unformattedString) {
|
abilityUsePattern.useMatch(it.unformattedString) {
|
||||||
lastUsage[group("name")] = TimeMark.now()
|
lastUsage[group("name")] = TimeMark.now()
|
||||||
}
|
}
|
||||||
abilitySwitchPattern.useMatch(it.unformattedString) {
|
abilitySwitchPattern.useMatch(it.unformattedString) {
|
||||||
abilityOverride = group("ability")
|
abilityOverride = group("ability")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
fun onWorldReady(event: WorldReadyEvent) {
|
fun onWorldReady(event: WorldReadyEvent) {
|
||||||
lobbyJoinTime = TimeMark.now()
|
lobbyJoinTime = TimeMark.now()
|
||||||
abilityOverride = null
|
abilityOverride = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
fun onProfileSwitch(event: ProfileSwitchEvent) {
|
fun onProfileSwitch(event: ProfileSwitchEvent) {
|
||||||
lastUsage.clear()
|
lastUsage.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
val abilityUsePattern = Pattern.compile("You used your (?<name>.*) Pickaxe Ability!")
|
val abilityUsePattern = Pattern.compile("You used your (?<name>.*) Pickaxe Ability!")
|
||||||
val fuelPattern = Pattern.compile("Fuel: .*/(?<maxFuel>$SHORT_NUMBER_FORMAT)")
|
val fuelPattern = Pattern.compile("Fuel: .*/(?<maxFuel>$SHORT_NUMBER_FORMAT)")
|
||||||
|
val pickaxeAbilityCooldownPattern = Pattern.compile("Your pickaxe ability is on cooldown for (?<remainingCooldown>$TIME_PATTERN)\\.")
|
||||||
|
|
||||||
data class PickaxeAbilityData(
|
data class PickaxeAbilityData(
|
||||||
val name: String,
|
val name: String,
|
||||||
val cooldown: Duration,
|
val cooldown: Duration,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getCooldownFromLore(itemStack: ItemStack): PickaxeAbilityData? {
|
fun getCooldownFromLore(itemStack: ItemStack): PickaxeAbilityData? {
|
||||||
val lore = itemStack.loreAccordingToNbt
|
val lore = itemStack.loreAccordingToNbt
|
||||||
if (!lore.any { it.unformattedString.contains("Breaking Power") })
|
if (!lore.any { it.unformattedString.contains("Breaking Power") })
|
||||||
return null
|
return null
|
||||||
val cooldown = lore.firstNotNullOfOrNull {
|
val ability = AbilityUtils.getAbilities(itemStack).firstOrNull() ?: return null
|
||||||
cooldownPattern.useMatch(it.unformattedString) {
|
return PickaxeAbilityData(ability.name, ability.cooldown ?: return null)
|
||||||
parseTimePattern(group("cooldown"))
|
}
|
||||||
}
|
|
||||||
} ?: return null
|
|
||||||
val name = lore.firstNotNullOfOrNull {
|
|
||||||
abilityPattern.useMatch(it.unformattedString) {
|
|
||||||
group("name")
|
|
||||||
}
|
|
||||||
} ?: return null
|
|
||||||
return PickaxeAbilityData(name, cooldown)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
val cooldownPattern = Pattern.compile("Cooldown: (?<cooldown>$TIME_PATTERN)")
|
||||||
|
val abilitySwitchPattern =
|
||||||
|
Pattern.compile("You selected (?<ability>.*) as your Pickaxe Ability\\. This ability will apply to all of your pickaxes!")
|
||||||
|
|
||||||
val cooldownPattern = Pattern.compile("Cooldown: (?<cooldown>$TIME_PATTERN)")
|
@Subscribe
|
||||||
val abilityPattern = Pattern.compile("(⦾ )?Ability: (?<name>.*) {2}RIGHT CLICK")
|
fun renderHud(event: HudRenderEvent) {
|
||||||
val abilitySwitchPattern =
|
if (!TConfig.cooldownEnabled) return
|
||||||
Pattern.compile("You selected (?<ability>.*) as your Pickaxe Ability\\. This ability will apply to all of your pickaxes!")
|
if (!event.isRenderingCursor) return
|
||||||
|
var ability = getCooldownFromLore(MC.player?.getStackInHand(Hand.MAIN_HAND) ?: return) ?: return
|
||||||
|
defaultAbilityDurations[ability.name] = ability.cooldown
|
||||||
@Subscribe
|
val ao = abilityOverride
|
||||||
fun renderHud(event: HudRenderEvent) {
|
if (ao != ability.name && ao != null) {
|
||||||
if (!TConfig.cooldownEnabled) return
|
ability = PickaxeAbilityData(ao, defaultAbilityDurations[ao] ?: 120.seconds)
|
||||||
var ability = getCooldownFromLore(MC.player?.getStackInHand(Hand.MAIN_HAND) ?: return) ?: return
|
}
|
||||||
defaultAbilityDurations[ability.name] = ability.cooldown
|
event.context.matrices.push()
|
||||||
val ao = abilityOverride
|
event.context.matrices.translate(MC.window.scaledWidth / 2F, MC.window.scaledHeight / 2F, 0F)
|
||||||
if (ao != ability.name && ao != null) {
|
event.context.matrices.scale(TConfig.cooldownScale.toFloat(), TConfig.cooldownScale.toFloat(), 1F)
|
||||||
ability = PickaxeAbilityData(ao, defaultAbilityDurations[ao] ?: 120.seconds)
|
RenderCircleProgress.renderCircle(
|
||||||
}
|
event.context, Identifier.of("firmament", "textures/gui/circle.png"),
|
||||||
event.context.matrices.push()
|
getCooldownPercentage(ability.name, ability.cooldown).toFloat(),
|
||||||
event.context.matrices.translate(MC.window.scaledWidth / 2F, MC.window.scaledHeight / 2F, 0F)
|
0f, 1f, 0f, 1f
|
||||||
event.context.matrices.scale(TConfig.cooldownScale.toFloat(), TConfig.cooldownScale.toFloat(), 1F)
|
)
|
||||||
RenderCircleProgress.renderCircle(
|
event.context.matrices.pop()
|
||||||
event.context, Identifier.of("firmament", "textures/gui/circle.png"),
|
}
|
||||||
getCooldownPercentage(ability.name, ability.cooldown).toFloat(),
|
|
||||||
0f, 1f, 0f, 1f
|
|
||||||
)
|
|
||||||
event.context.matrices.pop()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.features.texturepack
|
package moe.nea.firmament.features.texturepack
|
||||||
|
|
||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
@@ -6,120 +5,120 @@ import com.google.gson.JsonPrimitive
|
|||||||
import moe.nea.firmament.util.useMatch
|
import moe.nea.firmament.util.useMatch
|
||||||
|
|
||||||
abstract class NumberMatcher {
|
abstract class NumberMatcher {
|
||||||
abstract fun test(number: Number): Boolean
|
abstract fun test(number: Number): Boolean
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun parse(jsonElement: JsonElement): NumberMatcher? {
|
fun parse(jsonElement: JsonElement): NumberMatcher? {
|
||||||
if (jsonElement is JsonPrimitive) {
|
if (jsonElement is JsonPrimitive) {
|
||||||
if (jsonElement.isString) {
|
if (jsonElement.isString) {
|
||||||
val string = jsonElement.asString
|
val string = jsonElement.asString
|
||||||
return parseRange(string) ?: parseOperator(string)
|
return parseRange(string) ?: parseOperator(string)
|
||||||
}
|
}
|
||||||
if (jsonElement.isNumber) {
|
if (jsonElement.isNumber) {
|
||||||
val number = jsonElement.asNumber
|
val number = jsonElement.asNumber
|
||||||
val hasDecimals = (number.toString().contains("."))
|
val hasDecimals = (number.toString().contains("."))
|
||||||
return MatchNumberExact(if (hasDecimals) number.toLong() else number.toDouble())
|
return MatchNumberExact(if (hasDecimals) number.toLong() else number.toDouble())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private val intervalSpec =
|
private val intervalSpec =
|
||||||
"(?<beginningOpen>[\\[\\(])(?<beginning>[0-9.]+)?,(?<ending>[0-9.]+)?(?<endingOpen>[\\]\\)])"
|
"(?<beginningOpen>[\\[\\(])(?<beginning>[0-9.]+)?,(?<ending>[0-9.]+)?(?<endingOpen>[\\]\\)])"
|
||||||
.toPattern()
|
.toPattern()
|
||||||
|
|
||||||
fun parseRange(string: String): RangeMatcher? {
|
fun parseRange(string: String): RangeMatcher? {
|
||||||
intervalSpec.useMatch<Nothing>(string) {
|
intervalSpec.useMatch<Nothing>(string) {
|
||||||
// Open in the set-theory sense, meaning does not include its end.
|
// Open in the set-theory sense, meaning does not include its end.
|
||||||
val beginningOpen = group("beginningOpen") == "("
|
val beginningOpen = group("beginningOpen") == "("
|
||||||
val endingOpen = group("endingOpen") == ")"
|
val endingOpen = group("endingOpen") == ")"
|
||||||
val beginning = group("beginning")?.toDouble()
|
val beginning = group("beginning")?.toDouble()
|
||||||
val ending = group("ending")?.toDouble()
|
val ending = group("ending")?.toDouble()
|
||||||
return RangeMatcher(beginning, !beginningOpen, ending, !endingOpen)
|
return RangeMatcher(beginning, !beginningOpen, ending, !endingOpen)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Operator(val operator: String) {
|
enum class Operator(val operator: String) {
|
||||||
LESS("<") {
|
LESS("<") {
|
||||||
override fun matches(comparisonResult: Int): Boolean {
|
override fun matches(comparisonResult: Int): Boolean {
|
||||||
return comparisonResult < 0
|
return comparisonResult < 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
LESS_EQUALS("<=") {
|
LESS_EQUALS("<=") {
|
||||||
override fun matches(comparisonResult: Int): Boolean {
|
override fun matches(comparisonResult: Int): Boolean {
|
||||||
return comparisonResult <= 0
|
return comparisonResult <= 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GREATER(">") {
|
GREATER(">") {
|
||||||
override fun matches(comparisonResult: Int): Boolean {
|
override fun matches(comparisonResult: Int): Boolean {
|
||||||
return comparisonResult > 0
|
return comparisonResult > 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GREATER_EQUALS(">=") {
|
GREATER_EQUALS(">=") {
|
||||||
override fun matches(comparisonResult: Int): Boolean {
|
override fun matches(comparisonResult: Int): Boolean {
|
||||||
return comparisonResult >= 0
|
return comparisonResult >= 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
;
|
;
|
||||||
|
|
||||||
abstract fun matches(comparisonResult: Int): Boolean
|
abstract fun matches(comparisonResult: Int): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
private val operatorPattern = "(?<operator>${Operator.entries.joinToString("|") {it.operator}})(?<value>[0-9.]+)".toPattern()
|
private val operatorPattern =
|
||||||
|
"(?<operator>${Operator.entries.joinToString("|") { it.operator }})(?<value>[0-9.]+)".toPattern()
|
||||||
|
|
||||||
fun parseOperator(string: String): OperatorMatcher? {
|
fun parseOperator(string: String): OperatorMatcher? {
|
||||||
operatorPattern.useMatch<Nothing>(string) {
|
return operatorPattern.useMatch(string) {
|
||||||
val operatorName = group("operator")
|
val operatorName = group("operator")
|
||||||
val operator = Operator.entries.find { it.operator == operatorName }!!
|
val operator = Operator.entries.find { it.operator == operatorName }!!
|
||||||
val value = group("value").toDouble()
|
val value = group("value").toDouble()
|
||||||
return OperatorMatcher(operator, value)
|
OperatorMatcher(operator, value)
|
||||||
}
|
}
|
||||||
return null
|
}
|
||||||
}
|
|
||||||
|
|
||||||
data class OperatorMatcher(val operator: Operator, val value: Double) : NumberMatcher() {
|
data class OperatorMatcher(val operator: Operator, val value: Double) : NumberMatcher() {
|
||||||
override fun test(number: Number): Boolean {
|
override fun test(number: Number): Boolean {
|
||||||
return operator.matches(number.toDouble().compareTo(value))
|
return operator.matches(number.toDouble().compareTo(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
data class MatchNumberExact(val number: Number) : NumberMatcher() {
|
data class MatchNumberExact(val number: Number) : NumberMatcher() {
|
||||||
override fun test(number: Number): Boolean {
|
override fun test(number: Number): Boolean {
|
||||||
return when (this.number) {
|
return when (this.number) {
|
||||||
is Double -> number.toDouble() == this.number.toDouble()
|
is Double -> number.toDouble() == this.number.toDouble()
|
||||||
else -> number.toLong() == this.number.toLong()
|
else -> number.toLong() == this.number.toLong()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class RangeMatcher(
|
data class RangeMatcher(
|
||||||
val beginning: Double?,
|
val beginning: Double?,
|
||||||
val beginningInclusive: Boolean,
|
val beginningInclusive: Boolean,
|
||||||
val ending: Double?,
|
val ending: Double?,
|
||||||
val endingInclusive: Boolean,
|
val endingInclusive: Boolean,
|
||||||
) : NumberMatcher() {
|
) : NumberMatcher() {
|
||||||
override fun test(number: Number): Boolean {
|
override fun test(number: Number): Boolean {
|
||||||
val value = number.toDouble()
|
val value = number.toDouble()
|
||||||
if (beginning != null) {
|
if (beginning != null) {
|
||||||
if (beginningInclusive) {
|
if (beginningInclusive) {
|
||||||
if (value < beginning) return false
|
if (value < beginning) return false
|
||||||
} else {
|
} else {
|
||||||
if (value <= beginning) return false
|
if (value <= beginning) return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ending != null) {
|
if (ending != null) {
|
||||||
if (endingInclusive) {
|
if (endingInclusive) {
|
||||||
if (value > ending) return false
|
if (value > ending) return false
|
||||||
} else {
|
} else {
|
||||||
if (value >= ending) return false
|
if (value >= ending) return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/main/kotlin/util/ErrorUtil.kt
Normal file
16
src/main/kotlin/util/ErrorUtil.kt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
|
import moe.nea.firmament.Firmament
|
||||||
|
|
||||||
|
object ErrorUtil {
|
||||||
|
var aggressiveErrors = run {
|
||||||
|
Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") } || Firmament.DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame
|
||||||
|
inline fun softError(message: String) {
|
||||||
|
if (aggressiveErrors) error(message)
|
||||||
|
else Firmament.logger.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,7 +4,9 @@ import io.github.moulberry.repo.data.Coordinate
|
|||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||||
|
import net.minecraft.client.option.GameOptions
|
||||||
import net.minecraft.client.render.WorldRenderer
|
import net.minecraft.client.render.WorldRenderer
|
||||||
|
import net.minecraft.item.Item
|
||||||
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
|
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
|
||||||
import net.minecraft.registry.BuiltinRegistries
|
import net.minecraft.registry.BuiltinRegistries
|
||||||
import net.minecraft.registry.RegistryKeys
|
import net.minecraft.registry.RegistryKeys
|
||||||
@@ -16,79 +18,82 @@ import moe.nea.firmament.events.TickEvent
|
|||||||
|
|
||||||
object MC {
|
object MC {
|
||||||
|
|
||||||
private val messageQueue = ConcurrentLinkedQueue<Text>()
|
private val messageQueue = ConcurrentLinkedQueue<Text>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
TickEvent.subscribe("MC:push") {
|
TickEvent.subscribe("MC:push") {
|
||||||
while (true) {
|
while (true) {
|
||||||
inGameHud.chatHud.addMessage(messageQueue.poll() ?: break)
|
inGameHud.chatHud.addMessage(messageQueue.poll() ?: break)
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
(nextTickTodos.poll() ?: break).invoke()
|
(nextTickTodos.poll() ?: break).invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendChat(text: Text) {
|
fun sendChat(text: Text) {
|
||||||
if (instance.isOnThread)
|
if (instance.isOnThread)
|
||||||
inGameHud.chatHud.addMessage(text)
|
inGameHud.chatHud.addMessage(text)
|
||||||
else
|
else
|
||||||
messageQueue.add(text)
|
messageQueue.add(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendServerCommand(command: String) {
|
fun sendServerCommand(command: String) {
|
||||||
val nh = player?.networkHandler ?: return
|
val nh = player?.networkHandler ?: return
|
||||||
nh.sendPacket(
|
nh.sendPacket(
|
||||||
CommandExecutionC2SPacket(
|
CommandExecutionC2SPacket(
|
||||||
command,
|
command,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendServerChat(text: String) {
|
fun sendServerChat(text: String) {
|
||||||
player?.networkHandler?.sendChatMessage(text)
|
player?.networkHandler?.sendChatMessage(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendCommand(command: String) {
|
fun sendCommand(command: String) {
|
||||||
player?.networkHandler?.sendCommand(command)
|
player?.networkHandler?.sendCommand(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMainThread(block: () -> Unit) {
|
fun onMainThread(block: () -> Unit) {
|
||||||
if (instance.isOnThread)
|
if (instance.isOnThread)
|
||||||
block()
|
block()
|
||||||
else
|
else
|
||||||
instance.send(block)
|
instance.send(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val nextTickTodos = ConcurrentLinkedQueue<() -> Unit>()
|
private val nextTickTodos = ConcurrentLinkedQueue<() -> Unit>()
|
||||||
fun nextTick(function: () -> Unit) {
|
fun nextTick(function: () -> Unit) {
|
||||||
nextTickTodos.add(function)
|
nextTickTodos.add(function)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline val resourceManager get() = (instance.resourceManager as ReloadableResourceManagerImpl)
|
inline val resourceManager get() = (instance.resourceManager as ReloadableResourceManagerImpl)
|
||||||
inline val worldRenderer: WorldRenderer get() = instance.worldRenderer
|
inline val worldRenderer: WorldRenderer get() = instance.worldRenderer
|
||||||
inline val networkHandler get() = player?.networkHandler
|
inline val networkHandler get() = player?.networkHandler
|
||||||
inline val instance get() = MinecraftClient.getInstance()
|
inline val instance get() = MinecraftClient.getInstance()
|
||||||
inline val keyboard get() = instance.keyboard
|
inline val keyboard get() = instance.keyboard
|
||||||
inline val textureManager get() = instance.textureManager
|
inline val interactionManager get() = instance.interactionManager
|
||||||
inline val inGameHud get() = instance.inGameHud
|
inline val textureManager get() = instance.textureManager
|
||||||
inline val font get() = instance.textRenderer
|
inline val options get() = instance.options
|
||||||
inline val soundManager get() = instance.soundManager
|
inline val inGameHud get() = instance.inGameHud
|
||||||
inline val player get() = instance.player
|
inline val font get() = instance.textRenderer
|
||||||
inline val camera get() = instance.cameraEntity
|
inline val soundManager get() = instance.soundManager
|
||||||
inline val guiAtlasManager get() = instance.guiAtlasManager
|
inline val player get() = instance.player
|
||||||
inline val world get() = instance.world
|
inline val camera get() = instance.cameraEntity
|
||||||
inline var screen
|
inline val guiAtlasManager get() = instance.guiAtlasManager
|
||||||
get() = instance.currentScreen
|
inline val world get() = instance.world
|
||||||
set(value) = instance.setScreen(value)
|
inline var screen
|
||||||
inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*>
|
get() = instance.currentScreen
|
||||||
inline val window get() = instance.window
|
set(value) = instance.setScreen(value)
|
||||||
inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager
|
inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*>
|
||||||
val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup()
|
inline val window get() = instance.window
|
||||||
val defaultItems = defaultRegistries.getWrapperOrThrow(RegistryKeys.ITEM)
|
inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager
|
||||||
|
val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup()
|
||||||
|
inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries
|
||||||
|
val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getWrapperOrThrow(RegistryKeys.ITEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val Coordinate.blockPos: BlockPos
|
val Coordinate.blockPos: BlockPos
|
||||||
get() = BlockPos(x, y, z)
|
get() = BlockPos(x, y, z)
|
||||||
|
|||||||
@@ -1,44 +1,52 @@
|
|||||||
|
|
||||||
|
|
||||||
package moe.nea.firmament.util
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
class TimeMark private constructor(private val timeMark: Long) : Comparable<TimeMark> {
|
class TimeMark private constructor(private val timeMark: Long) : Comparable<TimeMark> {
|
||||||
fun passedTime() = if (timeMark == 0L) Duration.INFINITE else (System.currentTimeMillis() - timeMark).milliseconds
|
fun passedTime() =
|
||||||
|
if (timeMark == 0L) Duration.INFINITE
|
||||||
|
else (System.currentTimeMillis() - timeMark).milliseconds
|
||||||
|
|
||||||
operator fun minus(other: TimeMark): Duration {
|
fun passedAt(fakeNow: TimeMark) =
|
||||||
if (other.timeMark == timeMark)
|
if (timeMark == 0L) Duration.INFINITE
|
||||||
return 0.milliseconds
|
else (fakeNow.timeMark - timeMark).milliseconds
|
||||||
if (other.timeMark == 0L)
|
|
||||||
return Duration.INFINITE
|
|
||||||
if (timeMark == 0L)
|
|
||||||
return -Duration.INFINITE
|
|
||||||
return (timeMark - other.timeMark).milliseconds
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
operator fun minus(other: TimeMark): Duration {
|
||||||
fun now() = TimeMark(System.currentTimeMillis())
|
if (other.timeMark == timeMark)
|
||||||
fun farPast() = TimeMark(0L)
|
return 0.milliseconds
|
||||||
fun ago(timeDelta: Duration): TimeMark {
|
if (other.timeMark == 0L)
|
||||||
if (timeDelta.isFinite()) {
|
return Duration.INFINITE
|
||||||
return TimeMark(System.currentTimeMillis() - timeDelta.inWholeMilliseconds)
|
if (timeMark == 0L)
|
||||||
}
|
return -Duration.INFINITE
|
||||||
require(timeDelta.isPositive())
|
return (timeMark - other.timeMark).milliseconds
|
||||||
return farPast()
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
companion object {
|
||||||
return timeMark.hashCode()
|
fun now() = TimeMark(System.currentTimeMillis())
|
||||||
}
|
fun farPast() = TimeMark(0L)
|
||||||
|
fun ago(timeDelta: Duration): TimeMark {
|
||||||
|
if (timeDelta.isFinite()) {
|
||||||
|
return TimeMark(System.currentTimeMillis() - timeDelta.inWholeMilliseconds)
|
||||||
|
}
|
||||||
|
require(timeDelta.isPositive())
|
||||||
|
return farPast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun hashCode(): Int {
|
||||||
return other is TimeMark && other.timeMark == timeMark
|
return timeMark.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun compareTo(other: TimeMark): Int {
|
override fun equals(other: Any?): Boolean {
|
||||||
return this.timeMark.compareTo(other.timeMark)
|
return other is TimeMark && other.timeMark == timeMark
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "https://time.is/$timeMark"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun compareTo(other: TimeMark): Int {
|
||||||
|
return this.timeMark.compareTo(other.timeMark)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
138
src/main/kotlin/util/mc/SNbtFormatter.kt
Normal file
138
src/main/kotlin/util/mc/SNbtFormatter.kt
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
package moe.nea.firmament.util.mc
|
||||||
|
|
||||||
|
import net.minecraft.nbt.NbtByte
|
||||||
|
import net.minecraft.nbt.NbtByteArray
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.nbt.NbtDouble
|
||||||
|
import net.minecraft.nbt.NbtElement
|
||||||
|
import net.minecraft.nbt.NbtEnd
|
||||||
|
import net.minecraft.nbt.NbtFloat
|
||||||
|
import net.minecraft.nbt.NbtInt
|
||||||
|
import net.minecraft.nbt.NbtIntArray
|
||||||
|
import net.minecraft.nbt.NbtList
|
||||||
|
import net.minecraft.nbt.NbtLong
|
||||||
|
import net.minecraft.nbt.NbtLongArray
|
||||||
|
import net.minecraft.nbt.NbtShort
|
||||||
|
import net.minecraft.nbt.NbtString
|
||||||
|
import net.minecraft.nbt.visitor.NbtElementVisitor
|
||||||
|
|
||||||
|
class SNbtFormatter private constructor() : NbtElementVisitor {
|
||||||
|
private val result = StringBuilder()
|
||||||
|
private var indent = 0
|
||||||
|
private fun writeIndent() {
|
||||||
|
result.append("\t".repeat(indent))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun pushIndent() {
|
||||||
|
indent++
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun popIndent() {
|
||||||
|
indent--
|
||||||
|
}
|
||||||
|
|
||||||
|
fun apply(element: NbtElement): StringBuilder {
|
||||||
|
element.accept(this)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun visitString(element: NbtString) {
|
||||||
|
result.append(NbtString.escape(element.asString()))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitByte(element: NbtByte) {
|
||||||
|
result.append(element.numberValue()).append("b")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitShort(element: NbtShort) {
|
||||||
|
result.append(element.shortValue()).append("s")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitInt(element: NbtInt) {
|
||||||
|
result.append(element.intValue())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLong(element: NbtLong) {
|
||||||
|
result.append(element.longValue()).append("L")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFloat(element: NbtFloat) {
|
||||||
|
result.append(element.floatValue()).append("f")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDouble(element: NbtDouble) {
|
||||||
|
result.append(element.doubleValue()).append("d")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitArrayContents(array: List<NbtElement>) {
|
||||||
|
array.forEachIndexed { index, element ->
|
||||||
|
writeIndent()
|
||||||
|
element.accept(this)
|
||||||
|
if (array.size != index + 1) {
|
||||||
|
result.append(",")
|
||||||
|
}
|
||||||
|
result.append("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeArray(arrayTypeTag: String, array: List<NbtElement>) {
|
||||||
|
result.append("[").append(arrayTypeTag).append("\n")
|
||||||
|
pushIndent()
|
||||||
|
visitArrayContents(array)
|
||||||
|
popIndent()
|
||||||
|
writeIndent()
|
||||||
|
result.append("]")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitByteArray(element: NbtByteArray) {
|
||||||
|
writeArray("B;", element)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIntArray(element: NbtIntArray) {
|
||||||
|
writeArray("I;", element)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLongArray(element: NbtLongArray) {
|
||||||
|
writeArray("L;", element)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitList(element: NbtList) {
|
||||||
|
writeArray("", element)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCompound(compound: NbtCompound) {
|
||||||
|
result.append("{\n")
|
||||||
|
pushIndent()
|
||||||
|
val keys = compound.keys.sorted()
|
||||||
|
keys.forEachIndexed { index, key ->
|
||||||
|
writeIndent()
|
||||||
|
val element = compound[key] ?: error("Key '$key' found but not present in compound: $compound")
|
||||||
|
val escapedName = if (key.matches(SIMPLE_NAME)) key else NbtString.escape(key)
|
||||||
|
result.append(escapedName).append(": ")
|
||||||
|
element.accept(this)
|
||||||
|
if (keys.size != index + 1) {
|
||||||
|
result.append(",")
|
||||||
|
}
|
||||||
|
result.append("\n")
|
||||||
|
}
|
||||||
|
popIndent()
|
||||||
|
writeIndent()
|
||||||
|
result.append("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEnd(element: NbtEnd) {
|
||||||
|
result.append("END")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun prettify(nbt: NbtElement): String {
|
||||||
|
return SNbtFormatter().apply(nbt).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun NbtElement.toPrettyString() = prettify(this)
|
||||||
|
|
||||||
|
private val SIMPLE_NAME = "[A-Za-z0-9._+-]+".toRegex()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
|
@file:OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class)
|
||||||
|
|
||||||
package moe.nea.firmament.util
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
import java.util.regex.Matcher
|
import java.util.regex.Matcher
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import org.intellij.lang.annotations.Language
|
import org.intellij.lang.annotations.Language
|
||||||
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.contracts.InvocationKind
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
import kotlin.experimental.ExperimentalTypeInference
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.minutes
|
import kotlin.time.Duration.Companion.minutes
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
@@ -10,10 +16,14 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
inline fun <T> String.ifMatches(regex: Regex, block: (MatchResult) -> T): T? =
|
inline fun <T> String.ifMatches(regex: Regex, block: (MatchResult) -> T): T? =
|
||||||
regex.matchEntire(this)?.let(block)
|
regex.matchEntire(this)?.let(block)
|
||||||
|
|
||||||
inline fun <T> Pattern.useMatch(string: String, block: Matcher.() -> T): T? =
|
inline fun <T> Pattern.useMatch(string: String, block: Matcher.() -> T): T? {
|
||||||
matcher(string)
|
contract {
|
||||||
|
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
|
||||||
|
}
|
||||||
|
return matcher(string)
|
||||||
.takeIf(Matcher::matches)
|
.takeIf(Matcher::matches)
|
||||||
?.let(block)
|
?.let(block)
|
||||||
|
}
|
||||||
|
|
||||||
@Language("RegExp")
|
@Language("RegExp")
|
||||||
val TIME_PATTERN = "[0-9]+[ms]"
|
val TIME_PATTERN = "[0-9]+[ms]"
|
||||||
|
|||||||
138
src/main/kotlin/util/skyblock/AbilityUtils.kt
Normal file
138
src/main/kotlin/util/skyblock/AbilityUtils.kt
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
package moe.nea.firmament.util.skyblock
|
||||||
|
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import moe.nea.firmament.util.ErrorUtil
|
||||||
|
import moe.nea.firmament.util.directLiteralStringContent
|
||||||
|
import moe.nea.firmament.util.mc.loreAccordingToNbt
|
||||||
|
import moe.nea.firmament.util.parseShortNumber
|
||||||
|
import moe.nea.firmament.util.parseTimePattern
|
||||||
|
import moe.nea.firmament.util.unformattedString
|
||||||
|
import moe.nea.firmament.util.useMatch
|
||||||
|
|
||||||
|
object AbilityUtils {
|
||||||
|
data class ItemAbility(
|
||||||
|
val name: String,
|
||||||
|
val hasPowerScroll: Boolean,
|
||||||
|
val activation: AbilityActivation,
|
||||||
|
val manaCost: Int?,
|
||||||
|
val descriptionLines: List<Text>,
|
||||||
|
val cooldown: Duration?,
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class AbilityActivation(
|
||||||
|
val label: String
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
val RIGHT_CLICK = AbilityActivation("RIGHT CLICK")
|
||||||
|
val SNEAK_RIGHT_CLICK = AbilityActivation("SNEAK RIGHT CLICK")
|
||||||
|
val SNEAK = AbilityActivation("SNEAK")
|
||||||
|
val EMPTY = AbilityActivation("")
|
||||||
|
fun of(text: String?): AbilityActivation {
|
||||||
|
val trimmed = text?.trim()
|
||||||
|
if (trimmed.isNullOrBlank())
|
||||||
|
return EMPTY
|
||||||
|
return AbilityActivation(trimmed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val abilityNameRegex = "Ability: (?<name>.*?) *".toPattern()
|
||||||
|
private fun findAbility(iterator: ListIterator<Text>): ItemAbility? {
|
||||||
|
if (!iterator.hasNext()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val line = iterator.next()
|
||||||
|
// The actual information about abilities is stored in the siblings
|
||||||
|
if (line.directLiteralStringContent != "") return null
|
||||||
|
var powerScroll: Boolean = false // This should instead determine the power scroll based on text colour
|
||||||
|
var abilityName: String? = null
|
||||||
|
var activation: String? = null
|
||||||
|
var hasProcessedActivation = false
|
||||||
|
for (sibling in line.siblings) {
|
||||||
|
val directContent = sibling.directLiteralStringContent ?: continue
|
||||||
|
if (directContent == "⦾ ") {
|
||||||
|
powerScroll = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (!hasProcessedActivation && abilityName != null) {
|
||||||
|
hasProcessedActivation = true
|
||||||
|
activation = directContent
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
abilityNameRegex.useMatch<Nothing>(directContent) {
|
||||||
|
abilityName = group("name")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (abilityName != null) {
|
||||||
|
ErrorUtil.softError("Found abilityName $abilityName without finding but encountered unprocessable element in: $line")
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (abilityName == null) return null
|
||||||
|
val descriptionLines = mutableListOf<Text>()
|
||||||
|
var manaCost: Int? = null
|
||||||
|
var cooldown: Duration? = null
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val descriptionLine = iterator.next()
|
||||||
|
if (descriptionLine.unformattedString == "") break
|
||||||
|
var nextIsManaCost = false
|
||||||
|
var isSpecialLine = false
|
||||||
|
var nextIsDuration = false
|
||||||
|
for (sibling in descriptionLine.siblings) {
|
||||||
|
val directContent = sibling.directLiteralStringContent ?: continue
|
||||||
|
if ("Mana Cost: " == directContent) { // TODO: 'Soulflow Cost: ' support (or maybe a generic 'XXX Cost: ')
|
||||||
|
nextIsManaCost = true
|
||||||
|
isSpecialLine = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ("Cooldown: " == directContent) {
|
||||||
|
nextIsDuration = true
|
||||||
|
isSpecialLine = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (nextIsDuration) {
|
||||||
|
nextIsDuration = false
|
||||||
|
cooldown = parseTimePattern(directContent)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (nextIsManaCost) {
|
||||||
|
nextIsManaCost = false
|
||||||
|
manaCost = parseShortNumber(directContent).toInt()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (isSpecialLine) {
|
||||||
|
ErrorUtil.softError("Unknown special line segment: '$sibling' in '$descriptionLine'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isSpecialLine) {
|
||||||
|
descriptionLines.add(descriptionLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ItemAbility(
|
||||||
|
abilityName,
|
||||||
|
powerScroll,
|
||||||
|
AbilityActivation.of(activation),
|
||||||
|
manaCost,
|
||||||
|
descriptionLines,
|
||||||
|
cooldown
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAbilities(lore: List<Text>): List<ItemAbility> {
|
||||||
|
val iterator = lore.listIterator()
|
||||||
|
val abilities = mutableListOf<ItemAbility>()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
findAbility(iterator)?.let(abilities::add)
|
||||||
|
}
|
||||||
|
|
||||||
|
return abilities
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAbilities(itemStack: ItemStack): List<ItemAbility> {
|
||||||
|
return getAbilities(itemStack.loreAccordingToNbt)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -90,6 +90,8 @@ fun CharSequence.removeColorCodes(keepNonColorCodes: Boolean = false): String {
|
|||||||
val Text.unformattedString: String
|
val Text.unformattedString: String
|
||||||
get() = string.removeColorCodes()
|
get() = string.removeColorCodes()
|
||||||
|
|
||||||
|
val Text.directLiteralStringContent: String? get() = (this.content as? PlainTextContent)?.string()
|
||||||
|
|
||||||
fun Text.allSiblings(): List<Text> = listOf(this) + siblings.flatMap { it.allSiblings() }
|
fun Text.allSiblings(): List<Text> = listOf(this) + siblings.flatMap { it.allSiblings() }
|
||||||
|
|
||||||
fun MutableText.withColor(formatting: Formatting) = this.styled { it.withColor(formatting).withItalic(false) }
|
fun MutableText.withColor(formatting: Formatting) = this.styled { it.withColor(formatting).withItalic(false) }
|
||||||
|
|||||||
@@ -182,8 +182,9 @@
|
|||||||
"firmament.config.power-user.copy-texture-pack-id": "Copy Texture Pack Id",
|
"firmament.config.power-user.copy-texture-pack-id": "Copy Texture Pack Id",
|
||||||
"firmament.config.power-user.copy-skull-texture": "Copy Placed Skull Id",
|
"firmament.config.power-user.copy-skull-texture": "Copy Placed Skull Id",
|
||||||
"firmament.config.power-user.entity-data": "Show Entity Data",
|
"firmament.config.power-user.entity-data": "Show Entity Data",
|
||||||
"firmament.config.power-user.copy-nbt-data": "Copy NBT data",
|
"firmament.config.power-user.copy-nbt-data": "Copy ExtraAttributes data",
|
||||||
"firmament.config.power-user.copy-lore": "Copy Name + Lore",
|
"firmament.config.power-user.copy-lore": "Copy Name + Lore",
|
||||||
|
"firmament.config.power-user.copy-item-stack": "Copy ItemStack",
|
||||||
"firmament.config.power-user": "Power Users",
|
"firmament.config.power-user": "Power Users",
|
||||||
"firmament.tooltip.skyblockid": "SkyBlock Id: %s",
|
"firmament.tooltip.skyblockid": "SkyBlock Id: %s",
|
||||||
"firmament.tooltip.copied.skyblockid.fail": "Failed to copy SkyBlock Id",
|
"firmament.tooltip.copied.skyblockid.fail": "Failed to copy SkyBlock Id",
|
||||||
@@ -194,6 +195,7 @@
|
|||||||
"firmament.tooltip.copied.skull.fail": "Failed to copy skull id.",
|
"firmament.tooltip.copied.skull.fail": "Failed to copy skull id.",
|
||||||
"firmament.tooltip.copied.nbt": "Copied NBT data",
|
"firmament.tooltip.copied.nbt": "Copied NBT data",
|
||||||
"firmament.tooltip.copied.lore": "Copied Name and Lore",
|
"firmament.tooltip.copied.lore": "Copied Name and Lore",
|
||||||
|
"firmament.tooltip.copied.stack": "Copied ItemStack",
|
||||||
"firmament.config.compatibility": "Intermod Features",
|
"firmament.config.compatibility": "Intermod Features",
|
||||||
"firmament.config.compatibility.explosion-enabled": "Redirect Enhanced Explosions",
|
"firmament.config.compatibility.explosion-enabled": "Redirect Enhanced Explosions",
|
||||||
"firmament.config.compatibility.explosion-power": "Enhanced Explosion Power",
|
"firmament.config.compatibility.explosion-power": "Enhanced Explosion Power",
|
||||||
|
|||||||
@@ -22,3 +22,8 @@ mutable field net/minecraft/screen/slot/Slot y I
|
|||||||
accessible field net/minecraft/entity/player/PlayerEntity PLAYER_MODEL_PARTS Lnet/minecraft/entity/data/TrackedData;
|
accessible field net/minecraft/entity/player/PlayerEntity PLAYER_MODEL_PARTS Lnet/minecraft/entity/data/TrackedData;
|
||||||
accessible field net/minecraft/client/render/WorldRenderer chunks Lnet/minecraft/client/render/BuiltChunkStorage;
|
accessible field net/minecraft/client/render/WorldRenderer chunks Lnet/minecraft/client/render/BuiltChunkStorage;
|
||||||
|
|
||||||
|
# Fix package-private access methods
|
||||||
|
accessible method net/minecraft/registry/entry/RegistryEntry$Reference setRegistryKey (Lnet/minecraft/registry/RegistryKey;)V
|
||||||
|
accessible method net/minecraft/entity/LivingEntity getHitbox ()Lnet/minecraft/util/math/Box;
|
||||||
|
accessible method net/minecraft/registry/entry/RegistryEntryList$Named <init> (Lnet/minecraft/registry/entry/RegistryEntryOwner;Lnet/minecraft/registry/tag/TagKey;)V
|
||||||
|
accessible method net/minecraft/registry/entry/RegistryEntry$Reference setValue (Ljava/lang/Object;)V
|
||||||
|
|||||||
29
src/test/kotlin/root.kt
Normal file
29
src/test/kotlin/root.kt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package moe.nea.firmament.test
|
||||||
|
|
||||||
|
import net.minecraft.Bootstrap
|
||||||
|
import net.minecraft.SharedConstants
|
||||||
|
import moe.nea.firmament.util.TimeMark
|
||||||
|
|
||||||
|
object FirmTestBootstrap {
|
||||||
|
val loadStart = TimeMark.now()
|
||||||
|
|
||||||
|
init {
|
||||||
|
println("Bootstrap started at $loadStart")
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
SharedConstants.createGameVersion()
|
||||||
|
Bootstrap.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
val loadEnd = TimeMark.now()
|
||||||
|
|
||||||
|
val loadDuration = loadStart.passedAt(loadEnd)
|
||||||
|
|
||||||
|
init {
|
||||||
|
println("Bootstrap completed at $loadEnd after $loadDuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bootstrapMinecraft() {
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/test/kotlin/testutil/ItemResources.kt
Normal file
30
src/test/kotlin/testutil/ItemResources.kt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package moe.nea.firmament.test.testutil
|
||||||
|
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.nbt.NbtCompound
|
||||||
|
import net.minecraft.nbt.NbtOps
|
||||||
|
import net.minecraft.nbt.StringNbtReader
|
||||||
|
import moe.nea.firmament.test.FirmTestBootstrap
|
||||||
|
|
||||||
|
object ItemResources {
|
||||||
|
init {
|
||||||
|
FirmTestBootstrap.bootstrapMinecraft()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadString(path: String): String {
|
||||||
|
require(!path.startsWith("/"))
|
||||||
|
return ItemResources::class.java.classLoader
|
||||||
|
.getResourceAsStream(path)!!
|
||||||
|
.readAllBytes().decodeToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadSNbt(path: String): NbtCompound {
|
||||||
|
return StringNbtReader.parse(loadString(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadItem(name: String): ItemStack {
|
||||||
|
// TODO: make the load work with enchantments
|
||||||
|
return ItemStack.CODEC.parse(NbtOps.INSTANCE, loadSNbt("testdata/items/$name.snbt"))
|
||||||
|
.getOrThrow { IllegalStateException("Could not load test item '$name': $it") }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
|
package moe.nea.firmament.test.util
|
||||||
package moe.nea.firmament.test
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import net.minecraft.Bootstrap
|
||||||
|
import net.minecraft.SharedConstants
|
||||||
import moe.nea.firmament.util.removeColorCodes
|
import moe.nea.firmament.util.removeColorCodes
|
||||||
|
|
||||||
|
|
||||||
class ColorCode {
|
class ColorCodeTest {
|
||||||
@Test
|
@Test
|
||||||
fun testWhatever() {
|
fun testWhatever() {
|
||||||
Assertions.assertEquals("", "".removeColorCodes().toString())
|
Assertions.assertEquals("", "".removeColorCodes().toString())
|
||||||
79
src/test/kotlin/util/skyblock/AbilityUtilsTest.kt
Normal file
79
src/test/kotlin/util/skyblock/AbilityUtilsTest.kt
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package moe.nea.firmament.test.util.skyblock
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import kotlin.time.Duration.Companion.minutes
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import moe.nea.firmament.test.testutil.ItemResources
|
||||||
|
import moe.nea.firmament.util.skyblock.AbilityUtils
|
||||||
|
import moe.nea.firmament.util.unformattedString
|
||||||
|
|
||||||
|
class AbilityUtilsTest {
|
||||||
|
|
||||||
|
fun List<AbilityUtils.ItemAbility>.stripDescriptions() = map {
|
||||||
|
it.copy(descriptionLines = it.descriptionLines.map { Text.literal(it.unformattedString) })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUnpoweredDrill() {
|
||||||
|
Assertions.assertEquals(
|
||||||
|
listOf(
|
||||||
|
AbilityUtils.ItemAbility(
|
||||||
|
"Pickobulus",
|
||||||
|
false,
|
||||||
|
AbilityUtils.AbilityActivation.RIGHT_CLICK,
|
||||||
|
null,
|
||||||
|
listOf("Throw your pickaxe to create an",
|
||||||
|
"explosion mining all ores in a 3 block",
|
||||||
|
"radius.").map(Text::literal),
|
||||||
|
48.seconds
|
||||||
|
)
|
||||||
|
),
|
||||||
|
AbilityUtils.getAbilities(ItemResources.loadItem("titanium-drill")).stripDescriptions()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPoweredPickaxe() {
|
||||||
|
Assertions.assertEquals(
|
||||||
|
listOf(
|
||||||
|
AbilityUtils.ItemAbility(
|
||||||
|
"Mining Speed Boost",
|
||||||
|
true,
|
||||||
|
AbilityUtils.AbilityActivation.RIGHT_CLICK,
|
||||||
|
null,
|
||||||
|
listOf("Grants +200% ⸕ Mining Speed for",
|
||||||
|
"10s.").map(Text::literal),
|
||||||
|
2.minutes
|
||||||
|
)
|
||||||
|
),
|
||||||
|
AbilityUtils.getAbilities(ItemResources.loadItem("diamond-pickaxe")).stripDescriptions()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAOTV() {
|
||||||
|
Assertions.assertEquals(
|
||||||
|
listOf(
|
||||||
|
AbilityUtils.ItemAbility(
|
||||||
|
"Instant Transmission", true, AbilityUtils.AbilityActivation.RIGHT_CLICK, 23,
|
||||||
|
listOf("Teleport 12 blocks ahead of you and",
|
||||||
|
"gain +50 ✦ Speed for 3 seconds.").map(Text::literal),
|
||||||
|
null
|
||||||
|
),
|
||||||
|
AbilityUtils.ItemAbility(
|
||||||
|
"Ether Transmission",
|
||||||
|
false,
|
||||||
|
AbilityUtils.AbilityActivation.SNEAK_RIGHT_CLICK,
|
||||||
|
90,
|
||||||
|
listOf("Teleport to your targeted block up",
|
||||||
|
"to 61 blocks away.",
|
||||||
|
"Soulflow Cost: 1").map(Text::literal),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
),
|
||||||
|
AbilityUtils.getAbilities(ItemResources.loadItem("aspect-of-the-void")).stripDescriptions()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/test/resources/testdata/items/aspect-of-the-void.snbt
vendored
Normal file
59
src/test/resources/testdata/items/aspect-of-the-void.snbt
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
components: {
|
||||||
|
"minecraft:attribute_modifiers": {
|
||||||
|
modifiers: [
|
||||||
|
],
|
||||||
|
show_in_tooltip: 0b
|
||||||
|
},
|
||||||
|
"minecraft:custom_data": {
|
||||||
|
donated_museum: 1b,
|
||||||
|
enchantments: {
|
||||||
|
ultimate_wise: 5
|
||||||
|
},
|
||||||
|
ethermerge: 1b,
|
||||||
|
gems: {
|
||||||
|
},
|
||||||
|
id: "ASPECT_OF_THE_VOID",
|
||||||
|
modifier: "heroic",
|
||||||
|
originTag: "ASPECT_OF_THE_VOID",
|
||||||
|
power_ability_scroll: "SAPPHIRE_POWER_SCROLL",
|
||||||
|
timestamp: 1641640380000L,
|
||||||
|
tuned_transmission: 4,
|
||||||
|
uuid: "b0572534-eb14-46cd-90c6-0df878fd56a2"
|
||||||
|
},
|
||||||
|
"minecraft:custom_name": '{"extra":[{"color":"dark_purple","text":"Heroic Aspect of the Void"}],"italic":false,"text":""}',
|
||||||
|
"minecraft:enchantment_glint_override": 1b,
|
||||||
|
"minecraft:hide_additional_tooltip": {
|
||||||
|
},
|
||||||
|
"minecraft:lore": [
|
||||||
|
'{"extra":[{"color":"gray","text":"Damage: "},{"color":"red","text":"+120"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Strength: "},{"color":"red","text":"+132 "},{"color":"blue","text":"(+32)"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Bonus Attack Speed: "},{"color":"red","text":"+3% "},{"color":"blue","text":"(+3%)"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Intelligence: "},{"color":"green","text":"+80 "},{"color":"blue","text":"(+80)"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[" ",{"color":"dark_gray","text":"["},{"color":"gray","text":"✎"},{"color":"dark_gray","text":"]"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":""},{"bold":true,"color":"light_purple","text":"Ultimate Wise V"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Reduces the ability mana cost of this"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"item by "},{"color":"green","text":"50%"},{"color":"gray","text":"."}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"bold":true,"color":"aqua","text":"⦾ "},{"color":"gold","text":"Ability: Instant Transmission "},{"bold":true,"color":"yellow","text":"RIGHT CLICK"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Teleport "},{"color":"green","text":"12 blocks"},{"color":"gray","text":" ahead of you and"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"gain "},{"color":"green","text":"+50 "},{"color":"white","text":"✦ Speed"},{"color":"gray","text":" for "},{"color":"green","text":"3 seconds"},{"color":"gray","text":"."}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"dark_gray","text":"Mana Cost: "},{"color":"dark_aqua","text":"23"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gold","text":"Ability: Ether Transmission "},{"bold":true,"color":"yellow","text":"SNEAK RIGHT CLICK"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Teleport to your targeted block up"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"to "},{"color":"green","text":"61 blocks "},{"color":"gray","text":"away."}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"dark_gray","text":"Soulflow Cost: "},{"color":"dark_aqua","text":"1"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"dark_gray","text":"Mana Cost: "},{"color":"dark_aqua","text":"90"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"bold":true,"color":"dark_gray","text":"* "},{"color":"dark_gray","text":"Co-op Soulbound "},{"bold":true,"color":"dark_gray","text":"*"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"bold":true,"color":"dark_purple","text":"EPIC SWORD"}],"italic":false,"text":""}'
|
||||||
|
],
|
||||||
|
"minecraft:unbreakable": {
|
||||||
|
show_in_tooltip: 0b
|
||||||
|
}
|
||||||
|
},
|
||||||
|
count: 1,
|
||||||
|
id: "minecraft:diamond_shovel"
|
||||||
|
}
|
||||||
48
src/test/resources/testdata/items/diamond-pickaxe.snbt
vendored
Normal file
48
src/test/resources/testdata/items/diamond-pickaxe.snbt
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
components: {
|
||||||
|
"minecraft:attribute_modifiers": {
|
||||||
|
modifiers: [
|
||||||
|
],
|
||||||
|
show_in_tooltip: 0b
|
||||||
|
},
|
||||||
|
"minecraft:custom_data": {
|
||||||
|
enchantments: {
|
||||||
|
efficiency: 10
|
||||||
|
},
|
||||||
|
id: "DIAMOND_PICKAXE",
|
||||||
|
power_ability_scroll: "SAPPHIRE_POWER_SCROLL",
|
||||||
|
timestamp: 1659795180000L,
|
||||||
|
uuid: "d213f48e-d927-4748-a58c-eb80735025b7"
|
||||||
|
},
|
||||||
|
"minecraft:custom_name": '{"extra":[{"color":"green","text":"Diamond Pickaxe"}],"italic":false,"text":""}',
|
||||||
|
"minecraft:enchantments": {
|
||||||
|
levels: {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minecraft:hide_additional_tooltip": {
|
||||||
|
},
|
||||||
|
"minecraft:lore": [
|
||||||
|
'{"extra":[{"color":"dark_gray","text":"Breaking Power 4"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Damage: "},{"color":"red","text":"+30"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Mining Speed: "},{"color":"green","text":"+220"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":"Efficiency X"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Increases how quickly your tool"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"breaks blocks."}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"bold":true,"color":"aqua","text":"⦾ "},{"color":"gold","text":"Ability: Mining Speed Boost "},{"bold":true,"color":"yellow","text":"RIGHT CLICK"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Grants "},{"color":"gold","text":"+200% "},{"color":"gold","text":"⸕ Mining Speed "},{"color":"gray","text":"for"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"green","text":"10s"},{"color":"gray","text":"."}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"dark_gray","text":"Cooldown: "},{"color":"green","text":"120s"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"dark_gray","text":"This item can be reforged!"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"bold":true,"color":"green","text":"UNCOMMON PICKAXE"}],"italic":false,"text":""}'
|
||||||
|
],
|
||||||
|
"minecraft:unbreakable": {
|
||||||
|
show_in_tooltip: 0b
|
||||||
|
}
|
||||||
|
},
|
||||||
|
count: 1,
|
||||||
|
id: "minecraft:diamond_pickaxe"
|
||||||
|
}
|
||||||
97
src/test/resources/testdata/items/titanium-drill.snbt
vendored
Normal file
97
src/test/resources/testdata/items/titanium-drill.snbt
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
{
|
||||||
|
components: {
|
||||||
|
"minecraft:attribute_modifiers": {
|
||||||
|
modifiers: [
|
||||||
|
],
|
||||||
|
show_in_tooltip: 0b
|
||||||
|
},
|
||||||
|
"minecraft:custom_data": {
|
||||||
|
compact_blocks: 1023815,
|
||||||
|
donated_museum: 1b,
|
||||||
|
drill_fuel: 16621,
|
||||||
|
drill_part_fuel_tank: "titanium_fuel_tank",
|
||||||
|
drill_part_upgrade_module: "goblin_omelette_blue_cheese",
|
||||||
|
enchantments: {
|
||||||
|
compact: 10,
|
||||||
|
efficiency: 5,
|
||||||
|
experience: 3,
|
||||||
|
fortune: 3,
|
||||||
|
paleontologist: 2,
|
||||||
|
pristine: 5
|
||||||
|
},
|
||||||
|
gems: {
|
||||||
|
AMBER_0: {
|
||||||
|
quality: "PERFECT",
|
||||||
|
uuid: "d28be6ae-75eb-49e4-90d8-31759db18d79"
|
||||||
|
},
|
||||||
|
JADE_0: {
|
||||||
|
quality: "PERFECT",
|
||||||
|
uuid: "657fea0b-88e2-483d-9d2c-0b821797a55a"
|
||||||
|
},
|
||||||
|
MINING_0: {
|
||||||
|
quality: "PERFECT",
|
||||||
|
uuid: "257bdcd2-585b-48b9-9517-a2e841dc0574"
|
||||||
|
},
|
||||||
|
MINING_0_gem: "TOPAZ",
|
||||||
|
unlocked_slots: [
|
||||||
|
"JADE_0",
|
||||||
|
"MINING_0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
id: "TITANIUM_DRILL_4",
|
||||||
|
modifier: "auspicious",
|
||||||
|
rarity_upgrades: 1,
|
||||||
|
timestamp: 1700577120000L,
|
||||||
|
uuid: "367b85ab-5bb4-43b6-a055-084cbaaafc1c"
|
||||||
|
},
|
||||||
|
"minecraft:custom_name": '{"extra":[{"color":"light_purple","text":"Auspicious Titanium Drill DR-X655"}],"italic":false,"text":""}',
|
||||||
|
"minecraft:enchantment_glint_override": 1b,
|
||||||
|
"minecraft:hide_additional_tooltip": {
|
||||||
|
},
|
||||||
|
"minecraft:lore": [
|
||||||
|
'{"extra":[{"color":"dark_gray","text":"Breaking Power 9"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Damage: "},{"color":"red","text":"+75"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Mining Speed: "},{"color":"green","text":"+1,885 "},{"color":"blue","text":"(+75) "},{"color":"light_purple","text":"(+100)"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Pristine: "},{"color":"green","text":"+4.5 "},{"color":"light_purple","text":"(+2)"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Mining Fortune: "},{"color":"green","text":"+220 "},{"color":"blue","text":"(+20) "},{"color":"light_purple","text":"(+50)"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Mining Wisdom: "},{"color":"green","text":"+10"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[" ",{"color":"gold","text":"["},{"color":"gold","text":"⸕"},{"color":"gold","text":"] "},{"color":"gold","text":"["},{"color":"green","text":"☘"},{"color":"gold","text":"] "},{"color":"gold","text":"["},{"color":"yellow","text":"✦"},{"color":"gold","text":"]"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":"Compact X"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":"Efficiency V"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":"Experience III"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":"Fortune III"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":"Paleontologist II"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":"Prismatic V"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"green","text":"Titanium-Infused Fuel Tank."}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"gray","text":""},{"color":"dark_green","text":"25,000 Max Fuel Capacity."}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"gray","text":""},{"color":"green","text":"-4% Pickaxe Ability Cooldown."}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"gray","text":"Drill Engine: "},{"color":"red","text":"Not Installed"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"gray","text":"Increases "},{"color":"gold","text":"⸕ Mining Speed "},{"color":"gray","text":"with part"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"installed."}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"green","text":"Blue Cheese Goblin Omelette Part."}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Adds "},{"color":"green","text":"+1 Level "},{"color":"gray","text":"to all of your unlocked "},{"color":"dark_purple","text":"Heart of"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"dark_purple","text":"the Mountain "},{"color":"gray","text":"perks."}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":""},{"color":"gray","text":"Fuel: "},{"color":"dark_green","text":"16,621"},{"color":"dark_gray","text":"/25k"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gold","text":"Ability: Pickobulus "},{"bold":true,"color":"yellow","text":"RIGHT CLICK"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Throw your pickaxe to create an"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"explosion mining all ores in a "},{"color":"green","text":"3 "},{"color":"gray","text":"block"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"radius."}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"dark_gray","text":"Cooldown: "},{"color":"green","text":"48s"}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"blue","text":"Auspicious Bonus"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"color":"gray","text":"Grants "},{"color":"gold","text":"+0.9% "},{"color":"gold","text":"☘ Mining Fortune"},{"color":"gray","text":"."}],"italic":false,"text":""}',
|
||||||
|
'{"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"bold":true,"color":"dark_gray","text":"* "},{"color":"dark_gray","text":"Co-op Soulbound "},{"bold":true,"color":"dark_gray","text":"*"}],"italic":false,"text":""}',
|
||||||
|
'{"extra":[{"bold":true,"color":"light_purple","obfuscated":true,"text":"a"},"",{"bold":false,"extra":[" "],"italic":false,"obfuscated":false,"strikethrough":false,"text":"","underlined":false},{"bold":true,"color":"light_purple","text":"MYTHIC DRILL "},{"bold":true,"color":"light_purple","obfuscated":true,"text":"a"}],"italic":false,"text":""}'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
count: 1,
|
||||||
|
id: "minecraft:prismarine_shard"
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package moe.nea.firmament.annotations.process
|
||||||
|
|
||||||
|
import com.google.auto.service.AutoService
|
||||||
|
import com.google.devtools.ksp.containingFile
|
||||||
|
import com.google.devtools.ksp.processing.CodeGenerator
|
||||||
|
import com.google.devtools.ksp.processing.Dependencies
|
||||||
|
import com.google.devtools.ksp.processing.KSPLogger
|
||||||
|
import com.google.devtools.ksp.processing.Resolver
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessor
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessorProvider
|
||||||
|
import com.google.devtools.ksp.symbol.KSAnnotated
|
||||||
|
import com.google.devtools.ksp.symbol.KSClassDeclaration
|
||||||
|
import com.google.devtools.ksp.symbol.KSFile
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import java.io.OutputStreamWriter
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.util.TreeSet
|
||||||
|
|
||||||
|
class GameTestContainingClassProcessor(
|
||||||
|
val logger: KSPLogger,
|
||||||
|
val codeGenerator: CodeGenerator,
|
||||||
|
val sourceSetName: String,
|
||||||
|
) : SymbolProcessor {
|
||||||
|
|
||||||
|
|
||||||
|
@AutoService(SymbolProcessorProvider::class)
|
||||||
|
class Provider : SymbolProcessorProvider {
|
||||||
|
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
|
||||||
|
return GameTestContainingClassProcessor(
|
||||||
|
environment.logger,
|
||||||
|
environment.codeGenerator,
|
||||||
|
environment.options["firmament.sourceset"] ?: "main")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val allClasses: MutableSet<String> = TreeSet()
|
||||||
|
val allSources = mutableSetOf<KSFile>()
|
||||||
|
|
||||||
|
override fun process(resolver: Resolver): List<KSAnnotated> {
|
||||||
|
val annotated = resolver.getSymbolsWithAnnotation("net.minecraft.test.GameTest").toList()
|
||||||
|
annotated.forEach {
|
||||||
|
val containingClass = it.parent as KSClassDeclaration
|
||||||
|
allClasses.add(containingClass.qualifiedName!!.asString())
|
||||||
|
allSources.add(it.containingFile!!)
|
||||||
|
}
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createJson(): JsonObject {
|
||||||
|
return JsonObject().apply {
|
||||||
|
addProperty("schemaVersion", 1)
|
||||||
|
addProperty("id", "firmament-gametest")
|
||||||
|
addProperty("name", "Firmament Gametest")
|
||||||
|
addProperty("version", "1.0.0")
|
||||||
|
addProperty("environment", "*")
|
||||||
|
add("entrypoints", JsonObject().apply {
|
||||||
|
add("fabric-gametest", JsonArray().apply {
|
||||||
|
allClasses.forEach {
|
||||||
|
add(it)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun finish() {
|
||||||
|
if (allClasses.isEmpty()) return
|
||||||
|
val stream = codeGenerator.createNewFile(Dependencies(aggregating = true, *allSources.toTypedArray()),
|
||||||
|
"",
|
||||||
|
"fabric.mod",
|
||||||
|
"json")
|
||||||
|
val output = OutputStreamWriter(stream, StandardCharsets.UTF_8)
|
||||||
|
Gson().toJson(createJson(), output)
|
||||||
|
output.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user