diff options
Diffstat (limited to 'src/main/kotlin/moe/nea/firmament')
245 files changed, 0 insertions, 15933 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/Firmament.kt b/src/main/kotlin/moe/nea/firmament/Firmament.kt deleted file mode 100644 index c1801f4..0000000 --- a/src/main/kotlin/moe/nea/firmament/Firmament.kt +++ /dev/null @@ -1,148 +0,0 @@ - - -package moe.nea.firmament - -import com.mojang.brigadier.CommandDispatcher -import io.ktor.client.HttpClient -import io.ktor.client.plugins.UserAgent -import io.ktor.client.plugins.cache.HttpCache -import io.ktor.client.plugins.compression.ContentEncoding -import io.ktor.client.plugins.contentnegotiation.ContentNegotiation -import io.ktor.client.plugins.logging.LogLevel -import io.ktor.client.plugins.logging.Logging -import io.ktor.serialization.kotlinx.json.json -import java.io.InputStream -import java.nio.file.Files -import java.nio.file.Path -import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents -import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback -import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents -import net.fabricmc.loader.api.FabricLoader -import net.fabricmc.loader.api.Version -import net.fabricmc.loader.api.metadata.ModMetadata -import org.apache.logging.log4j.LogManager -import org.apache.logging.log4j.Logger -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.plus -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream -import kotlin.coroutines.EmptyCoroutineContext -import net.minecraft.client.render.chunk.SectionBuilder -import net.minecraft.command.CommandRegistryAccess -import net.minecraft.util.Identifier -import moe.nea.firmament.commands.registerFirmamentCommand -import moe.nea.firmament.events.ClientStartedEvent -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.events.ItemTooltipEvent -import moe.nea.firmament.events.ScreenRenderPostEvent -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.events.registration.registerFirmamentEvents -import moe.nea.firmament.features.FeatureManager -import moe.nea.firmament.repo.HypixelStaticData -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SBData -import moe.nea.firmament.util.data.IDataHolder - -object Firmament { - const val MOD_ID = "firmament" - - val DEBUG = System.getProperty("firmament.debug") == "true" - val DATA_DIR: Path = Path.of(".firmament").also { Files.createDirectories(it) } - val CONFIG_DIR: Path = Path.of("config/firmament").also { Files.createDirectories(it) } - val logger: Logger = LogManager.getLogger("Firmament") - private val metadata: ModMetadata by lazy { - FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().metadata - } - val version: Version by lazy { metadata.version } - - val json = Json { - prettyPrint = DEBUG - isLenient = true - ignoreUnknownKeys = true - encodeDefaults = true - } - - val httpClient by lazy { - HttpClient { - install(ContentNegotiation) { - json(json) - } - install(ContentEncoding) { - gzip() - deflate() - } - install(UserAgent) { - agent = "Firmament/$version" - } - if (DEBUG) - install(Logging) { - level = LogLevel.INFO - } - install(HttpCache) - } - } - - val globalJob = Job() - val coroutineScope = - CoroutineScope(EmptyCoroutineContext + CoroutineName("Firmament")) + SupervisorJob(globalJob) - - private fun registerCommands( - dispatcher: CommandDispatcher<FabricClientCommandSource>, - @Suppress("UNUSED_PARAMETER") - ctx: CommandRegistryAccess - ) { - registerFirmamentCommand(dispatcher) - CommandEvent.publish(CommandEvent(dispatcher, ctx, MC.networkHandler?.commandDispatcher)) - } - - @JvmStatic - fun onInitialize() { - } - - @JvmStatic - fun onClientInitialize() { - FeatureManager.subscribeEvents() - var tick = 0 - ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance -> - TickEvent.publish(TickEvent(tick++)) - }) - IDataHolder.registerEvents() - RepoManager.initialize() - SBData.init() - FeatureManager.autoload() - HypixelStaticData.spawnDataCollectionLoop() - ClientCommandRegistrationCallback.EVENT.register(this::registerCommands) - ClientLifecycleEvents.CLIENT_STARTED.register(ClientLifecycleEvents.ClientStarted { - ClientStartedEvent.publish(ClientStartedEvent()) - }) - ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { - logger.info("Shutting down Firmament coroutines") - globalJob.cancel() - }) - registerFirmamentEvents() - ItemTooltipCallback.EVENT.register { stack, context, type, lines -> - ItemTooltipEvent.publish(ItemTooltipEvent(stack, context, type, lines)) - } - ScreenEvents.AFTER_INIT.register(ScreenEvents.AfterInit { client, screen, scaledWidth, scaledHeight -> - ScreenEvents.afterRender(screen) - .register(ScreenEvents.AfterRender { screen, drawContext, mouseX, mouseY, tickDelta -> - ScreenRenderPostEvent.publish(ScreenRenderPostEvent(screen, mouseX, mouseY, tickDelta, drawContext)) - }) - }) - } - - - fun identifier(path: String) = Identifier.of(MOD_ID, path) - inline fun <reified T : Any> tryDecodeJsonFromStream(inputStream: InputStream): Result<T> { - return runCatching { - json.decodeFromStream<T>(inputStream) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt b/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt deleted file mode 100644 index 789364a..0000000 --- a/src/main/kotlin/moe/nea/firmament/apis/Profiles.kt +++ /dev/null @@ -1,194 +0,0 @@ - - -@file:UseSerializers(DashlessUUIDSerializer::class, InstantAsLongSerializer::class) - -package moe.nea.firmament.apis - -import io.github.moulberry.repo.constants.Leveling -import io.github.moulberry.repo.data.Rarity -import kotlinx.datetime.Instant -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.LegacyFormattingCode -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.assertNotNullOr -import moe.nea.firmament.util.json.DashlessUUIDSerializer -import moe.nea.firmament.util.json.InstantAsLongSerializer -import net.minecraft.util.DyeColor -import net.minecraft.util.Formatting -import java.util.* -import kotlin.reflect.KProperty1 - - -@Serializable -data class CollectionSkillData( - val items: Map<CollectionType, CollectionInfo> -) - -@Serializable -data class CollectionResponse( - val success: Boolean, - val collections: Map<String, CollectionSkillData> -) - -@Serializable -data class CollectionInfo( - val name: String, - val maxTiers: Int, - val tiers: List<CollectionTier> -) - -@Serializable -data class CollectionTier( - val tier: Int, - val amountRequired: Long, - val unlocks: List<String>, -) - - -@Serializable -data class Profiles( - val success: Boolean, - val profiles: List<Profile>? -) - -@Serializable -data class Profile( - @SerialName("profile_id") - val profileId: UUID, - @SerialName("cute_name") - val cuteName: String, - val selected: Boolean = false, - val members: Map<UUID, Member>, -) - -enum class Skill(val accessor: KProperty1<Member, Double>, val color: DyeColor, val icon: SkyblockId) { - FARMING(Member::experienceSkillFarming, DyeColor.YELLOW, SkyblockId("ROOKIE_HOE")), - FORAGING(Member::experienceSkillForaging, DyeColor.BROWN, SkyblockId("TREECAPITATOR_AXE")), - MINING(Member::experienceSkillMining, DyeColor.LIGHT_GRAY, SkyblockId("DIAMOND_PICKAXE")), - ALCHEMY(Member::experienceSkillAlchemy, DyeColor.PURPLE, SkyblockId("BREWING_STAND")), - TAMING(Member::experienceSkillTaming, DyeColor.GREEN, SkyblockId("SUPER_EGG")), - FISHING(Member::experienceSkillFishing, DyeColor.BLUE, SkyblockId("FARMER_ROD")), - RUNECRAFTING(Member::experienceSkillRunecrafting, DyeColor.PINK, SkyblockId("MUSIC_RUNE;1")), - CARPENTRY(Member::experienceSkillCarpentry, DyeColor.ORANGE, SkyblockId("WORKBENCH")), - COMBAT(Member::experienceSkillCombat, DyeColor.RED, SkyblockId("UNDEAD_SWORD")), - SOCIAL(Member::experienceSkillSocial, DyeColor.WHITE, SkyblockId("EGG_HUNT")), - ENCHANTING(Member::experienceSkillEnchanting, DyeColor.MAGENTA, SkyblockId("ENCHANTMENT_TABLE")), - ; - - fun getMaximumLevel(leveling: Leveling) = assertNotNullOr(leveling.maximumLevels[name.lowercase()]) { 50 } - - fun getLadder(leveling: Leveling): List<Int> { - if (this == SOCIAL) return leveling.socialExperienceRequiredPerLevel - if (this == RUNECRAFTING) return leveling.runecraftingExperienceRequiredPerLevel - return leveling.skillExperienceRequiredPerLevel - } -} - -enum class CollectionCategory(val skill: Skill?, val color: DyeColor, val icon: SkyblockId) { - FARMING(Skill.FARMING, DyeColor.YELLOW, SkyblockId("ROOKIE_HOE")), - FORAGING(Skill.FORAGING, DyeColor.BROWN, SkyblockId("TREECAPITATOR_AXE")), - MINING(Skill.MINING, DyeColor.LIGHT_GRAY, SkyblockId("DIAMOND_PICKAXE")), - FISHING(Skill.FISHING, DyeColor.BLUE, SkyblockId("FARMER_ROD")), - COMBAT(Skill.COMBAT, DyeColor.RED, SkyblockId("UNDEAD_SWORD")), - RIFT(null, DyeColor.PURPLE, SkyblockId("SKYBLOCK_MOTE")), -} - -@Serializable -@JvmInline -value class CollectionType(val string: String) { - val skyblockId get() = SkyblockId(string.replace(":", "-").replace("MUSHROOM_COLLECTION", "HUGE_MUSHROOM_2")) -} - -@Serializable -data class Member( - val pets: List<Pet> = listOf(), - @SerialName("coop_invitation") - val coopInvitation: CoopInvitation? = null, - @SerialName("experience_skill_farming") - val experienceSkillFarming: Double = 0.0, - @SerialName("experience_skill_alchemy") - val experienceSkillAlchemy: Double = 0.0, - @SerialName("experience_skill_combat") - val experienceSkillCombat: Double = 0.0, - @SerialName("experience_skill_taming") - val experienceSkillTaming: Double = 0.0, - @SerialName("experience_skill_social2") - val experienceSkillSocial: Double = 0.0, - @SerialName("experience_skill_enchanting") - val experienceSkillEnchanting: Double = 0.0, - @SerialName("experience_skill_fishing") - val experienceSkillFishing: Double = 0.0, - @SerialName("experience_skill_foraging") - val experienceSkillForaging: Double = 0.0, - @SerialName("experience_skill_mining") - val experienceSkillMining: Double = 0.0, - @SerialName("experience_skill_runecrafting") - val experienceSkillRunecrafting: Double = 0.0, - @SerialName("experience_skill_carpentry") - val experienceSkillCarpentry: Double = 0.0, - val collection: Map<CollectionType, Long> = mapOf() -) - -@Serializable -data class CoopInvitation( - val timestamp: Instant, - @SerialName("invited_by") - val invitedBy: UUID? = null, - val confirmed: Boolean, -) - -@JvmInline -@Serializable -value class PetType(val name: String) - -@Serializable -data class Pet( - val uuid: UUID? = null, - val type: PetType, - val exp: Double = 0.0, - val active: Boolean = false, - val tier: Rarity, - val candyUsed: Int = 0, - val heldItem: String? = null, - val skin: String? = null, -) { - val itemId get() = SkyblockId("${type.name};${tier.ordinal}") -} - -@Serializable -data class PlayerResponse( - val success: Boolean, - val player: PlayerData, -) - -@Serializable -data class PlayerData( - val uuid: UUID, - val firstLogin: Instant, - val lastLogin: Instant? = null, - @SerialName("playername") - val playerName: String, - val achievementsOneTime: List<String> = listOf(), - @SerialName("newPackageRank") - val packageRank: String? = null, - val monthlyPackageRank: String? = null, - val rankPlusColor: String = "GOLD" -) { - val rankPlusDyeColor = LegacyFormattingCode.values().find { it.name == rankPlusColor } ?: LegacyFormattingCode.GOLD - val rankData get() = RepoManager.neuRepo.constants.misc.ranks[if (monthlyPackageRank == "NONE" || monthlyPackageRank == null) packageRank else monthlyPackageRank] - fun getDisplayName(name: String = playerName) = rankData?.let { - ("§${it.color}[${it.tag}${rankPlusDyeColor.modern}" + - "${it.plus ?: ""}§${it.color}] $name") - } ?: "${Formatting.GRAY}$name" - - -} - -@Serializable -data class AshconNameLookup( - val username: String, - val uuid: UUID, -) diff --git a/src/main/kotlin/moe/nea/firmament/apis/Routes.kt b/src/main/kotlin/moe/nea/firmament/apis/Routes.kt deleted file mode 100644 index bf55a2d..0000000 --- a/src/main/kotlin/moe/nea/firmament/apis/Routes.kt +++ /dev/null @@ -1,95 +0,0 @@ - - -package moe.nea.firmament.apis - -import io.ktor.client.call.* -import io.ktor.client.request.* -import io.ktor.http.* -import io.ktor.util.* -import java.util.* -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.async -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import kotlin.collections.MutableMap -import kotlin.collections.listOf -import kotlin.collections.mutableMapOf -import kotlin.collections.set -import moe.nea.firmament.Firmament -import moe.nea.firmament.util.MinecraftDispatcher - -object Routes { - private val nameToUUID: MutableMap<String, Deferred<UUID?>> = CaseInsensitiveMap() - private val profiles: MutableMap<UUID, Deferred<Profiles?>> = mutableMapOf() - private val accounts: MutableMap<UUID, Deferred<PlayerData?>> = mutableMapOf() - private val UUIDToName: MutableMap<UUID, Deferred<String?>> = mutableMapOf() - - suspend fun getPlayerNameForUUID(uuid: UUID): String? { - return withContext(MinecraftDispatcher) { - UUIDToName.computeIfAbsent(uuid) { - async(Firmament.coroutineScope.coroutineContext) { - val response = Firmament.httpClient.get("https://api.ashcon.app/mojang/v2/user/$uuid") - if (!response.status.isSuccess()) return@async null - val data = response.body<AshconNameLookup>() - launch(MinecraftDispatcher) { - nameToUUID[data.username] = async { data.uuid } - } - data.username - } - } - }.await() - } - - suspend fun getUUIDForPlayerName(name: String): UUID? { - return withContext(MinecraftDispatcher) { - nameToUUID.computeIfAbsent(name) { - async(Firmament.coroutineScope.coroutineContext) { - val response = Firmament.httpClient.get("https://api.ashcon.app/mojang/v2/user/$name") - if (!response.status.isSuccess()) return@async null - val data = response.body<AshconNameLookup>() - launch(MinecraftDispatcher) { - UUIDToName[data.uuid] = async { data.username } - } - data.uuid - } - } - }.await() - } - - suspend fun getAccountData(uuid: UUID): PlayerData? { - return withContext(MinecraftDispatcher) { - accounts.computeIfAbsent(uuid) { - async(Firmament.coroutineScope.coroutineContext) { - val response = UrsaManager.request(listOf("v1", "hypixel","player", uuid.toString())) - if (!response.status.isSuccess()) { - launch(MinecraftDispatcher) { - @Suppress("DeferredResultUnused") - accounts.remove(uuid) - } - return@async null - } - response.body<PlayerResponse>().player - } - } - }.await() - } - - suspend fun getProfiles(uuid: UUID): Profiles? { - return withContext(MinecraftDispatcher) { - profiles.computeIfAbsent(uuid) { - async(Firmament.coroutineScope.coroutineContext) { - val response = UrsaManager.request(listOf("v1", "hypixel","profiles", uuid.toString())) - if (!response.status.isSuccess()) { - launch(MinecraftDispatcher) { - @Suppress("DeferredResultUnused") - profiles.remove(uuid) - } - return@async null - } - response.body<Profiles>() - } - } - }.await() - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/apis/UrsaManager.kt b/src/main/kotlin/moe/nea/firmament/apis/UrsaManager.kt deleted file mode 100644 index 13f7aef..0000000 --- a/src/main/kotlin/moe/nea/firmament/apis/UrsaManager.kt +++ /dev/null @@ -1,72 +0,0 @@ - - -package moe.nea.firmament.apis - -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.withContext -import moe.nea.firmament.Firmament -import net.minecraft.client.MinecraftClient -import java.time.Duration -import java.time.Instant -import java.util.* - -object UrsaManager { - private data class Token( - val validUntil: Instant, - val token: String, - val obtainedFrom: String, - ) { - fun isValid(host: String) = Instant.now().plusSeconds(60) < validUntil && obtainedFrom == host - } - - private var currentToken: Token? = null - private val lock = Mutex() - private fun getToken(host: String) = currentToken?.takeIf { it.isValid(host) } - - suspend fun request(path: List<String>): HttpResponse { - var didLock = false - try { - val host = "ursa.notenoughupdates.org" - var token = getToken(host) - if (token == null) { - lock.lock() - didLock = true - token = getToken(host) - } - val response = Firmament.httpClient.get { - url { - this.host = host - appendPathSegments(path, encodeSlash = true) - } - if (token == null) { - withContext(Dispatchers.IO) { - val mc = MinecraftClient.getInstance() - val serverId = UUID.randomUUID().toString() - mc.sessionService.joinServer(mc.session.uuidOrNull, mc.session.accessToken, serverId) - header("x-ursa-username", mc.session.username) - header("x-ursa-serverid", serverId) - } - } else { - header("x-ursa-token", token.token) - } - } - val savedToken = response.headers["x-ursa-token"] - if (savedToken != null) { - val validUntil = response.headers["x-ursa-expires"]?.toLongOrNull()?.let { Instant.ofEpochMilli(it) } - ?: (Instant.now() + Duration.ofMinutes(55)) - currentToken = Token(validUntil, savedToken, host) - } - if (response.status.value != 200) { - Firmament.logger.error("Failed to contact ursa minor: ${response.bodyAsText()}") - } - return response - } finally { - if (didLock) - lock.unlock() - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/commands/CaseInsensitiveLiteralCommandNode.kt b/src/main/kotlin/moe/nea/firmament/commands/CaseInsensitiveLiteralCommandNode.kt deleted file mode 100644 index 10772b0..0000000 --- a/src/main/kotlin/moe/nea/firmament/commands/CaseInsensitiveLiteralCommandNode.kt +++ /dev/null @@ -1,75 +0,0 @@ - - -package moe.nea.firmament.commands - -import com.mojang.brigadier.Command -import com.mojang.brigadier.RedirectModifier -import com.mojang.brigadier.StringReader -import com.mojang.brigadier.builder.LiteralArgumentBuilder -import com.mojang.brigadier.context.CommandContextBuilder -import com.mojang.brigadier.context.StringRange -import com.mojang.brigadier.exceptions.CommandSyntaxException -import com.mojang.brigadier.tree.CommandNode -import com.mojang.brigadier.tree.LiteralCommandNode -import java.util.function.Predicate - -class CaseInsensitiveLiteralCommandNode<S>( - literal: String, command: Command<S>?, requirement: Predicate<S>?, - redirect: CommandNode<S>?, modifier: RedirectModifier<S>?, forks: Boolean -) : LiteralCommandNode<S>( - literal.lowercase(), command, requirement, redirect, modifier, forks -) { - class Builder<S>(literal: String) : LiteralArgumentBuilder<S>(literal) { - override fun build(): LiteralCommandNode<S> { - val result = CaseInsensitiveLiteralCommandNode( - literal, - command, requirement, redirect, redirectModifier, isFork - ) - for (argument in arguments) { - result.addChild(argument) - } - return result - } - } - - override fun createBuilder(): LiteralArgumentBuilder<S> { - return Builder<S>(literal).also { - it.requires(requirement) - it.forward(redirect, redirectModifier, isFork) - if (command != null) - it.executes(command) - } - } - - override fun parse(reader: StringReader, contextBuilder: CommandContextBuilder<S>) { - val start = reader.cursor - val end = parse0(reader) - if (end > -1) { - contextBuilder.withNode(this, StringRange.between(start, end)) - return - } - - throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.literalIncorrect().createWithContext(reader, literal) - } - - override fun toString(): String { - return "<iliteral $literal>" - } - - private fun parse0(reader: StringReader): Int { - val start = reader.cursor - if (reader.canRead(literal.length)) { - val end = start + literal.length - if (reader.string.substring(start, end).equals(literal, true)) { - reader.cursor = end - if (!reader.canRead() || reader.peek() == ' ') { - return end - } else { - reader.cursor = start - } - } - } - return -1 - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/commands/RestArgumentType.kt b/src/main/kotlin/moe/nea/firmament/commands/RestArgumentType.kt deleted file mode 100644 index 361907f..0000000 --- a/src/main/kotlin/moe/nea/firmament/commands/RestArgumentType.kt +++ /dev/null @@ -1,15 +0,0 @@ - - -package moe.nea.firmament.commands - -import com.mojang.brigadier.StringReader -import com.mojang.brigadier.arguments.ArgumentType - -object RestArgumentType : ArgumentType<String> { - override fun parse(reader: StringReader): String { - val remaining = reader.remaining - reader.cursor += remaining.length - return remaining - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/commands/dsl.kt b/src/main/kotlin/moe/nea/firmament/commands/dsl.kt deleted file mode 100644 index d1f0d8c..0000000 --- a/src/main/kotlin/moe/nea/firmament/commands/dsl.kt +++ /dev/null @@ -1,118 +0,0 @@ - - -package moe.nea.firmament.commands - -import com.mojang.brigadier.arguments.ArgumentType -import com.mojang.brigadier.builder.ArgumentBuilder -import com.mojang.brigadier.builder.RequiredArgumentBuilder -import com.mojang.brigadier.context.CommandContext -import com.mojang.brigadier.suggestion.SuggestionProvider -import kotlinx.coroutines.launch -import moe.nea.firmament.Firmament -import moe.nea.firmament.util.MinecraftDispatcher -import moe.nea.firmament.util.iterate -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource -import java.lang.reflect.ParameterizedType -import java.lang.reflect.Type -import java.lang.reflect.TypeVariable - - -typealias DefaultSource = FabricClientCommandSource - - -inline val <T : CommandContext<*>> T.context get() = this -operator fun <T : Any, C : CommandContext<*>> C.get(arg: TypeSafeArg<T>): T { - return arg.get(this) -} - -fun literal( - name: String, - block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit -): CaseInsensitiveLiteralCommandNode.Builder<DefaultSource> = - CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>(name).also(block) - - -private fun normalizeGeneric(argument: Type): Class<*> { - return when (argument) { - is Class<*> -> argument - is TypeVariable<*> -> normalizeGeneric(argument.bounds[0]) - is ParameterizedType -> normalizeGeneric(argument.rawType) - else -> Any::class.java - } -} - -data class TypeSafeArg<T : Any>(val name: String, val argument: ArgumentType<T>) { - val argClass by lazy { - argument.javaClass - .iterate<Class<in ArgumentType<T>>> { - it.superclass - } - .flatMap { - it.genericInterfaces.toList() - } - .filterIsInstance<ParameterizedType>() - .find { it.rawType == ArgumentType::class.java }!! - .let { normalizeGeneric(it.actualTypeArguments[0]) } - } - - @JvmName("getWithThis") - fun <S> CommandContext<S>.get(): T = - get(this) - - - fun <S> get(ctx: CommandContext<S>): T { - try { - return ctx.getArgument(name, argClass) as T - } catch (e: Exception) { - if (ctx.child != null) { - return get(ctx.child) - } - throw e - } - } -} - - -fun <T : Any> argument( - name: String, - argument: ArgumentType<T>, - block: RequiredArgumentBuilder<DefaultSource, T>.(TypeSafeArg<T>) -> Unit -): RequiredArgumentBuilder<DefaultSource, T> = - RequiredArgumentBuilder.argument<DefaultSource, T>(name, argument).also { block(it, TypeSafeArg(name, argument)) } - -fun <T : ArgumentBuilder<DefaultSource, T>, AT : Any> T.thenArgument( - name: String, - argument: ArgumentType<AT>, - block: RequiredArgumentBuilder<DefaultSource, AT>.(TypeSafeArg<AT>) -> Unit -): T = then(argument(name, argument, block)) - -fun <T : RequiredArgumentBuilder<DefaultSource, String>> T.suggestsList(provider: CommandContext<DefaultSource>.() -> Iterable<String>) { - suggests(SuggestionProvider<DefaultSource> { context, builder -> - provider(context) - .asSequence() - .filter { it.startsWith(builder.remaining, ignoreCase = true) } - .forEach { - builder.suggest(it) - } - builder.buildFuture() - }) -} - -fun <T : ArgumentBuilder<DefaultSource, T>> T.thenLiteral( - name: String, - block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit -): T = - then(literal(name, block)) - -fun <T : ArgumentBuilder<DefaultSource, T>> T.then(node: ArgumentBuilder<DefaultSource, *>, block: T.() -> Unit): T = - then(node).also(block) - -fun <T : ArgumentBuilder<DefaultSource, T>> T.thenExecute(block: suspend CommandContext<DefaultSource>.() -> Unit): T = - executes { - Firmament.coroutineScope.launch(MinecraftDispatcher) { - block(it) - } - 1 - } - - diff --git a/src/main/kotlin/moe/nea/firmament/commands/rome.kt b/src/main/kotlin/moe/nea/firmament/commands/rome.kt deleted file mode 100644 index 015512d..0000000 --- a/src/main/kotlin/moe/nea/firmament/commands/rome.kt +++ /dev/null @@ -1,230 +0,0 @@ - - -package moe.nea.firmament.commands - -import com.mojang.brigadier.CommandDispatcher -import com.mojang.brigadier.arguments.StringArgumentType.string -import io.ktor.client.statement.bodyAsText -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource -import net.minecraft.text.Text -import moe.nea.firmament.apis.UrsaManager -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.features.debug.PowerUserTools -import moe.nea.firmament.features.inventory.buttons.InventoryButtons -import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen -import moe.nea.firmament.features.inventory.storageoverlay.StorageOverviewScreen -import moe.nea.firmament.gui.config.AllConfigsGui -import moe.nea.firmament.gui.config.BooleanHandler -import moe.nea.firmament.gui.config.ManagedOption -import moe.nea.firmament.repo.HypixelStaticData -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.FirmFormatters -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SBData -import moe.nea.firmament.util.ScreenUtil -import moe.nea.firmament.util.SkyblockId - - -fun firmamentCommand() = literal("firmament") { - thenLiteral("config") { - thenExecute { - AllConfigsGui.showAllGuis() - } - thenLiteral("toggle") { - thenArgument("config", string()) { config -> - suggestsList { - AllConfigsGui.allConfigs.asSequence().map { it.name }.asIterable() - } - thenArgument("property", string()) { property -> - suggestsList { - (AllConfigsGui.allConfigs.find { it.name == this[config] } ?: return@suggestsList listOf()) - .allOptions.entries.asSequence().filter { it.value.handler is BooleanHandler } - .map { it.key } - .asIterable() - } - thenExecute { - val config = this[config] - val property = this[property] - - val configObj = AllConfigsGui.allConfigs.find { it.name == config } - if (configObj == null) { - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.command.toggle.no-config-found", - config - ) - ) - return@thenExecute - } - val propertyObj = configObj.allOptions[property] - if (propertyObj == null) { - source.sendFeedback( - Text.stringifiedTranslatable("firmament.command.toggle.no-property-found", property) - ) - return@thenExecute - } - if (propertyObj.handler !is BooleanHandler) { - source.sendFeedback( - Text.stringifiedTranslatable("firmament.command.toggle.not-a-toggle", property) - ) - return@thenExecute - } - propertyObj as ManagedOption<Boolean> - propertyObj.value = !propertyObj.value - configObj.save() - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.command.toggle.toggled", configObj.labelText, - propertyObj.labelText, - Text.translatable("firmament.toggle.${propertyObj.value}") - ) - ) - } - } - } - } - } - thenLiteral("buttons") { - thenExecute { - InventoryButtons.openEditor() - } - } - thenLiteral("sendcoords") { - thenExecute { - val p = MC.player ?: return@thenExecute - MC.sendServerChat("x: ${p.blockX}, y: ${p.blockY}, z: ${p.blockZ}") - } - thenArgument("rest", RestArgumentType) { rest -> - thenExecute { - val p = MC.player ?: return@thenExecute - MC.sendServerChat("x: ${p.blockX}, y: ${p.blockY}, z: ${p.blockZ} ${this[rest]}") - } - } - } - thenLiteral("storageoverview") { - thenExecute { - ScreenUtil.setScreenLater(StorageOverviewScreen()) - MC.player?.networkHandler?.sendChatCommand("storage") - } - } - thenLiteral("storage") { - thenExecute { - ScreenUtil.setScreenLater(StorageOverlayScreen()) - MC.player?.networkHandler?.sendChatCommand("storage") - } - } - thenLiteral("repo") { - thenLiteral("reload") { - thenLiteral("fetch") { - thenExecute { - source.sendFeedback(Text.translatable("firmament.repo.reload.network")) // TODO better reporting - RepoManager.launchAsyncUpdate() - } - } - thenExecute { - source.sendFeedback(Text.translatable("firmament.repo.reload.disk")) - RepoManager.reload() - } - } - } - thenLiteral("price") { - thenArgument("item", string()) { item -> - suggestsList { RepoManager.neuRepo.items.items.keys } - thenExecute { - val itemName = SkyblockId(get(item)) - source.sendFeedback(Text.stringifiedTranslatable("firmament.price", itemName.neuItem)) - val bazaarData = HypixelStaticData.bazaarData[itemName] - if (bazaarData != null) { - source.sendFeedback(Text.translatable("firmament.price.bazaar")) - source.sendFeedback( - Text.stringifiedTranslatable("firmament.price.bazaar.productid", bazaarData.productId.bazaarId) - ) - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.price.bazaar.buy.price", - FirmFormatters.formatCommas(bazaarData.quickStatus.buyPrice, 1) - ) - ) - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.price.bazaar.buy.order", - bazaarData.quickStatus.buyOrders - ) - ) - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.price.bazaar.sell.price", - FirmFormatters.formatCommas(bazaarData.quickStatus.sellPrice, 1) - ) - ) - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.price.bazaar.sell.order", - bazaarData.quickStatus.sellOrders - ) - ) - } - val lowestBin = HypixelStaticData.lowestBin[itemName] - if (lowestBin != null) { - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.price.lowestbin", - FirmFormatters.formatCommas(lowestBin, 1) - ) - ) - } - } - } - } - thenLiteral("dev") { - thenLiteral("simulate") { - thenArgument("message", RestArgumentType) { message -> - thenExecute { - MC.instance.messageHandler.onGameMessage(Text.literal(get(message)), false) - } - } - } - thenLiteral("sbdata") { - thenExecute { - source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.profile", SBData.profileId)) - val locrawInfo = SBData.locraw - if (locrawInfo == null) { - source.sendFeedback(Text.translatable("firmament.sbinfo.nolocraw")) - } else { - source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.server", locrawInfo.server)) - source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.gametype", locrawInfo.gametype)) - source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.mode", locrawInfo.mode)) - source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.map", locrawInfo.map)) - } - } - } - thenLiteral("copyEntities") { - thenExecute { - val player = MC.player ?: return@thenExecute - player.world.getOtherEntities(player, player.boundingBox.expand(12.0)).forEach(PowerUserTools::showEntity) - } - } - thenLiteral("callUrsa") { - thenArgument("path", string()) { path -> - thenExecute { - source.sendFeedback(Text.translatable("firmament.ursa.debugrequest.start")) - val text = UrsaManager.request(this[path].split("/")).bodyAsText() - source.sendFeedback(Text.stringifiedTranslatable("firmament.ursa.debugrequest.result", text)) - } - } - } - } - CommandEvent.SubCommand.publish(CommandEvent.SubCommand(this@literal)) -} - - -fun registerFirmamentCommand(dispatcher: CommandDispatcher<FabricClientCommandSource>) { - val firmament = dispatcher.register(firmamentCommand()) - dispatcher.register(literal("firm") { - redirect(firmament) - }) -} - - - - diff --git a/src/main/kotlin/moe/nea/firmament/compat/SodiumChunkReloader.kt b/src/main/kotlin/moe/nea/firmament/compat/SodiumChunkReloader.kt deleted file mode 100644 index 4bb231a..0000000 --- a/src/main/kotlin/moe/nea/firmament/compat/SodiumChunkReloader.kt +++ /dev/null @@ -1,12 +0,0 @@ -package moe.nea.firmament.compat - -import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer -import moe.nea.firmament.mixins.accessor.sodium.AccessorSodiumWorldRenderer - -class SodiumChunkReloader : Runnable { - override fun run() { - (SodiumWorldRenderer.instanceNullable() as AccessorSodiumWorldRenderer) - .renderSectionManager_firmament - .updateChunks(false) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/AllowChatEvent.kt b/src/main/kotlin/moe/nea/firmament/events/AllowChatEvent.kt deleted file mode 100644 index 3069843..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/AllowChatEvent.kt +++ /dev/null @@ -1,16 +0,0 @@ - - -package moe.nea.firmament.events - -import moe.nea.firmament.util.unformattedString -import net.minecraft.text.Text - -/** - * Filter whether the user should see a chat message altogether. May or may not be called for every chat packet sent by - * the server. When that quality is desired, consider [ProcessChatEvent] instead. - */ -data class AllowChatEvent(val text: Text) : FirmamentEvent.Cancellable() { - val unformattedString = text.unformattedString - - companion object : FirmamentEventBus<AllowChatEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/AttackBlockEvent.kt b/src/main/kotlin/moe/nea/firmament/events/AttackBlockEvent.kt deleted file mode 100644 index bbaa81d..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/AttackBlockEvent.kt +++ /dev/null @@ -1,18 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.util.Hand -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Direction -import net.minecraft.world.World - -data class AttackBlockEvent( - val player: PlayerEntity, - val world: World, - val hand: Hand, - val blockPos: BlockPos, - val direction: Direction -) : FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<AttackBlockEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/BakeExtraModelsEvent.kt b/src/main/kotlin/moe/nea/firmament/events/BakeExtraModelsEvent.kt deleted file mode 100644 index f75bedc..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/BakeExtraModelsEvent.kt +++ /dev/null @@ -1,21 +0,0 @@ - -package moe.nea.firmament.events - -import java.util.function.Consumer -import net.minecraft.client.util.ModelIdentifier - -class BakeExtraModelsEvent( - private val addItemModel: Consumer<ModelIdentifier>, - private val addAnyModel: Consumer<ModelIdentifier>, -) : FirmamentEvent() { - - fun addNonItemModel(modelIdentifier: ModelIdentifier) { - this.addAnyModel.accept(modelIdentifier) - } - - fun addItemModel(modelIdentifier: ModelIdentifier) { - this.addItemModel.accept(modelIdentifier) - } - - companion object : FirmamentEventBus<BakeExtraModelsEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ClientStartedEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ClientStartedEvent.kt deleted file mode 100644 index 637916d..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ClientStartedEvent.kt +++ /dev/null @@ -1,6 +0,0 @@ - -package moe.nea.firmament.events - -class ClientStartedEvent : FirmamentEvent() { - companion object : FirmamentEventBus<ClientStartedEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/CommandEvent.kt b/src/main/kotlin/moe/nea/firmament/events/CommandEvent.kt deleted file mode 100644 index cc9cf45..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/CommandEvent.kt +++ /dev/null @@ -1,45 +0,0 @@ - - -package moe.nea.firmament.events - -import com.mojang.brigadier.CommandDispatcher -import com.mojang.brigadier.tree.LiteralCommandNode -import net.minecraft.command.CommandRegistryAccess -import moe.nea.firmament.commands.CaseInsensitiveLiteralCommandNode -import moe.nea.firmament.commands.DefaultSource -import moe.nea.firmament.commands.literal -import moe.nea.firmament.commands.thenLiteral - -data class CommandEvent( - val dispatcher: CommandDispatcher<DefaultSource>, - val ctx: CommandRegistryAccess, - val serverCommands: CommandDispatcher<*>?, -) : FirmamentEvent() { - companion object : FirmamentEventBus<CommandEvent>() - - /** - * Register subcommands to `/firm`. For new top level commands use [CommandEvent]. Cannot be used to register - * subcommands to other commands. - */ - data class SubCommand( - val builder: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>, - ) : FirmamentEvent() { - companion object : FirmamentEventBus<SubCommand>() - - fun subcommand(name: String, block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit) { - builder.thenLiteral(name, block) - } - } - - fun deleteCommand(name: String) { - dispatcher.root.children.removeIf { it.name.equals(name, ignoreCase = false) } - serverCommands?.root?.children?.removeIf { it.name.equals(name, ignoreCase = false) } - } - - fun register( - name: String, - block: CaseInsensitiveLiteralCommandNode.Builder<DefaultSource>.() -> Unit - ): LiteralCommandNode<DefaultSource> { - return dispatcher.register(literal(name, block)) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/CustomItemModelEvent.kt b/src/main/kotlin/moe/nea/firmament/events/CustomItemModelEvent.kt deleted file mode 100644 index 27524a9..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/CustomItemModelEvent.kt +++ /dev/null @@ -1,43 +0,0 @@ - - -package moe.nea.firmament.events - -import java.util.* -import net.minecraft.client.render.model.BakedModel -import net.minecraft.client.render.model.BakedModelManager -import net.minecraft.client.util.ModelIdentifier -import net.minecraft.item.ItemStack - -data class CustomItemModelEvent( - val itemStack: ItemStack, - var overrideModel: ModelIdentifier? = null, -) : FirmamentEvent() { - companion object : FirmamentEventBus<CustomItemModelEvent>() { - private val cache = IdentityHashMap<ItemStack?, Any>() - private val sentinelNull = Object() - - fun clearCache() { - cache.clear() - } - - @JvmStatic - fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? { - if (itemStack == null) return null - return publish(CustomItemModelEvent(itemStack)).overrideModel - } - - @JvmStatic - fun getModel(itemStack: ItemStack?, thing: BakedModelManager): BakedModel? { - if (itemStack == null) return null - val cachedValue = cache.getOrPut(itemStack) { - val modelId = getModelIdentifier(itemStack) ?: return@getOrPut sentinelNull - val bakedModel = thing.getModel(modelId) - if (bakedModel === thing.missingModel) return@getOrPut sentinelNull - bakedModel - } - if (cachedValue === sentinelNull) - return null - return cachedValue as BakedModel - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/EarlyResourceReloadEvent.kt b/src/main/kotlin/moe/nea/firmament/events/EarlyResourceReloadEvent.kt deleted file mode 100644 index ec8377a..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/EarlyResourceReloadEvent.kt +++ /dev/null @@ -1,10 +0,0 @@ - -package moe.nea.firmament.events - -import java.util.concurrent.Executor -import net.minecraft.resource.ResourceManager - -data class EarlyResourceReloadEvent(val resourceManager: ResourceManager, val preparationExecutor: Executor) : - FirmamentEvent() { - companion object : FirmamentEventBus<EarlyResourceReloadEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/EntityDespawnEvent.kt b/src/main/kotlin/moe/nea/firmament/events/EntityDespawnEvent.kt deleted file mode 100644 index 93dc477..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/EntityDespawnEvent.kt +++ /dev/null @@ -1,11 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.entity.Entity - -data class EntityDespawnEvent( - val entity: Entity?, val entityId: Int, - val reason: Entity.RemovalReason, -) : FirmamentEvent() { - companion object: FirmamentEventBus<EntityDespawnEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/EntityInteractionEvent.kt b/src/main/kotlin/moe/nea/firmament/events/EntityInteractionEvent.kt deleted file mode 100644 index 123ea39..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/EntityInteractionEvent.kt +++ /dev/null @@ -1,29 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.entity.Entity -import net.minecraft.util.Hand - -data class EntityInteractionEvent( - val kind: InteractionKind, - val entity: Entity, - val hand: Hand, -) : FirmamentEvent() { - companion object : FirmamentEventBus<EntityInteractionEvent>() - enum class InteractionKind { - /** - * Is sent when left-clicking an entity - */ - ATTACK, - - /** - * Is a fallback when [INTERACT_AT_LOCATION] fails - */ - INTERACT, - - /** - * Is tried first on right click - */ - INTERACT_AT_LOCATION, - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/EntityUpdateEvent.kt b/src/main/kotlin/moe/nea/firmament/events/EntityUpdateEvent.kt deleted file mode 100644 index d091984..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/EntityUpdateEvent.kt +++ /dev/null @@ -1,31 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.entity.Entity -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.data.DataTracker -import net.minecraft.network.packet.s2c.play.EntityAttributesS2CPacket - -/** - * This event is fired when some entity properties are updated. - * It is not fired for common changes like position, but is for less common ones, - * like health, tracked data, names, equipment. It is always fired - * *after* the values have been applied to the entity. - */ -sealed class EntityUpdateEvent : FirmamentEvent() { - companion object : FirmamentEventBus<EntityUpdateEvent>() - - abstract val entity: Entity - - data class AttributeUpdate( - override val entity: LivingEntity, - val attributes: List<EntityAttributesS2CPacket.Entry>, - ) : EntityUpdateEvent() - - data class TrackedDataUpdate( - override val entity: Entity, - val trackedValues: List<DataTracker.SerializedEntry<*>>, - ) : EntityUpdateEvent() - -// TODO: onEntityPassengersSet, onEntityAttach?, onEntityEquipmentUpdate, onEntityStatusEffect -} diff --git a/src/main/kotlin/moe/nea/firmament/events/FeaturesInitializedEvent.kt b/src/main/kotlin/moe/nea/firmament/events/FeaturesInitializedEvent.kt deleted file mode 100644 index ad2ad8a..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/FeaturesInitializedEvent.kt +++ /dev/null @@ -1,8 +0,0 @@ - -package moe.nea.firmament.events - -import moe.nea.firmament.features.FirmamentFeature - -data class FeaturesInitializedEvent(val features: List<FirmamentFeature>) : FirmamentEvent() { - companion object : FirmamentEventBus<FeaturesInitializedEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/FinalizeResourceManagerEvent.kt b/src/main/kotlin/moe/nea/firmament/events/FinalizeResourceManagerEvent.kt deleted file mode 100644 index c43ad3b..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/FinalizeResourceManagerEvent.kt +++ /dev/null @@ -1,10 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.resource.ReloadableResourceManagerImpl - -data class FinalizeResourceManagerEvent( - val resourceManager: ReloadableResourceManagerImpl, -) : FirmamentEvent() { - companion object : FirmamentEventBus<FinalizeResourceManagerEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/FirmamentEvent.kt b/src/main/kotlin/moe/nea/firmament/events/FirmamentEvent.kt deleted file mode 100644 index 1a93ef5..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/FirmamentEvent.kt +++ /dev/null @@ -1,38 +0,0 @@ - - -package moe.nea.firmament.events - -/** - * An event that can be fired by a [FirmamentEventBus]. - * - * Typically, that event bus is implemented as a companion object - * - * ``` - * class SomeEvent : FirmamentEvent() { - * companion object : FirmamentEventBus<SomeEvent>() - * } - * ``` - */ -abstract class FirmamentEvent { - /** - * A [FirmamentEvent] that can be [cancelled] - */ - abstract class Cancellable : FirmamentEvent() { - /** - * Cancels this is event. - * - * @see cancelled - */ - fun cancel() { - cancelled = true - } - - /** - * Whether this event is cancelled. - * - * Cancelled events will bypass handlers unless otherwise specified and will prevent the action that this - * event was originally fired for. - */ - var cancelled: Boolean = false - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/FirmamentEventBus.kt b/src/main/kotlin/moe/nea/firmament/events/FirmamentEventBus.kt deleted file mode 100644 index ee9e6c8..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/FirmamentEventBus.kt +++ /dev/null @@ -1,52 +0,0 @@ - - -package moe.nea.firmament.events - -import java.util.concurrent.CopyOnWriteArrayList -import moe.nea.firmament.Firmament -import moe.nea.firmament.util.MC - -/** - * A pubsub event bus. - * - * [subscribe] to events [publish]ed on this event bus. - * Subscriptions may not necessarily be delivered in the order of registering. - */ -open class FirmamentEventBus<T : FirmamentEvent> { - data class Handler<T>( - val invocation: (T) -> Unit, val receivesCancelled: Boolean, - var knownErrors: MutableSet<Class<*>> = mutableSetOf(), - ) - - private val toHandle: MutableList<Handler<T>> = CopyOnWriteArrayList() - fun subscribe(handle: (T) -> Unit) { - subscribe(false, handle) - } - - fun subscribe(receivesCancelled: Boolean, handle: (T) -> Unit) { - toHandle.add(Handler(handle, receivesCancelled)) - } - - fun publish(event: T): T { - for (function in toHandle) { - if (function.receivesCancelled || event !is FirmamentEvent.Cancellable || !event.cancelled) { - try { - function.invocation(event) - } catch (e: Exception) { - val klass = e.javaClass - if (!function.knownErrors.contains(klass) || Firmament.DEBUG) { - function.knownErrors.add(klass) - Firmament.logger.error("Caught exception during processing event $event by $function", e) - } - } - } - } - return event - } - - fun publishSync(event: T) { - MC.onMainThread { - publish(event) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/HandledScreenClickEvent.kt b/src/main/kotlin/moe/nea/firmament/events/HandledScreenClickEvent.kt deleted file mode 100644 index 4c3003c..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/HandledScreenClickEvent.kt +++ /dev/null @@ -1,10 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.screen.ingame.HandledScreen - -data class HandledScreenClickEvent(val screen: HandledScreen<*>, val mouseX: Double, val mouseY: Double, val button: Int) : - FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<HandledScreenClickEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/HandledScreenForegroundEvent.kt b/src/main/kotlin/moe/nea/firmament/events/HandledScreenForegroundEvent.kt deleted file mode 100644 index f16d30e..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/HandledScreenForegroundEvent.kt +++ /dev/null @@ -1,16 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.screen.ingame.HandledScreen - -data class HandledScreenForegroundEvent( - val screen: HandledScreen<*>, - val context: DrawContext, - val mouseX: Int, - val mouseY: Int, - val delta: Float -) : FirmamentEvent() { - companion object : FirmamentEventBus<HandledScreenForegroundEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/HandledScreenKeyPressedEvent.kt b/src/main/kotlin/moe/nea/firmament/events/HandledScreenKeyPressedEvent.kt deleted file mode 100644 index 7ec2abb..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/HandledScreenKeyPressedEvent.kt +++ /dev/null @@ -1,24 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.screen.ingame.HandledScreen -import net.minecraft.client.option.KeyBinding -import moe.nea.firmament.keybindings.IKeyBinding - -data class HandledScreenKeyPressedEvent( - val screen: HandledScreen<*>, - val keyCode: Int, - val scanCode: Int, - val modifiers: Int -) : FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<HandledScreenKeyPressedEvent>() - - fun matches(keyBinding: KeyBinding): Boolean { - return matches(IKeyBinding.minecraft(keyBinding)) - } - - fun matches(keyBinding: IKeyBinding): Boolean { - return keyBinding.matches(keyCode, scanCode, modifiers) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/HandledScreenPushREIEvent.kt b/src/main/kotlin/moe/nea/firmament/events/HandledScreenPushREIEvent.kt deleted file mode 100644 index 1bb495a..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/HandledScreenPushREIEvent.kt +++ /dev/null @@ -1,18 +0,0 @@ - - -package moe.nea.firmament.events - -import me.shedaniel.math.Rectangle -import net.minecraft.client.gui.screen.ingame.HandledScreen - -data class HandledScreenPushREIEvent( - val screen: HandledScreen<*>, - val rectangles: MutableList<Rectangle> = mutableListOf() -) : FirmamentEvent() { - - fun block(rectangle: Rectangle) { - rectangles.add(rectangle) - } - - companion object : FirmamentEventBus<HandledScreenPushREIEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/HotbarItemRenderEvent.kt b/src/main/kotlin/moe/nea/firmament/events/HotbarItemRenderEvent.kt deleted file mode 100644 index a1940e6..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/HotbarItemRenderEvent.kt +++ /dev/null @@ -1,17 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.item.ItemStack - -data class HotbarItemRenderEvent( - val item: ItemStack, - val context: DrawContext, - val x: Int, - val y: Int, - val tickDelta: RenderTickCounter, -) : FirmamentEvent() { - companion object : FirmamentEventBus<HotbarItemRenderEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/HudRenderEvent.kt b/src/main/kotlin/moe/nea/firmament/events/HudRenderEvent.kt deleted file mode 100644 index 555b3c8..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/HudRenderEvent.kt +++ /dev/null @@ -1,13 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.RenderTickCounter - -/** - * Called when hud elements should be rendered, before the screen, but after the world. - */ -data class HudRenderEvent(val context: DrawContext, val tickDelta: RenderTickCounter) : FirmamentEvent() { - companion object : FirmamentEventBus<HudRenderEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/IsSlotProtectedEvent.kt b/src/main/kotlin/moe/nea/firmament/events/IsSlotProtectedEvent.kt deleted file mode 100644 index cd431f7..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/IsSlotProtectedEvent.kt +++ /dev/null @@ -1,46 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.item.ItemStack -import net.minecraft.screen.slot.Slot -import net.minecraft.screen.slot.SlotActionType -import net.minecraft.text.Text -import moe.nea.firmament.util.CommonSoundEffects -import moe.nea.firmament.util.MC - -data class IsSlotProtectedEvent( - val slot: Slot?, - val actionType: SlotActionType, - var isProtected: Boolean, - val itemStackOverride: ItemStack?, - var silent: Boolean = false, -) : FirmamentEvent() { - val itemStack get() = itemStackOverride ?: slot!!.stack - - fun protect() { - isProtected = true - } - - fun protectSilent() { - if (!isProtected) { - silent = true - } - isProtected = true - } - - companion object : FirmamentEventBus<IsSlotProtectedEvent>() { - @JvmStatic - @JvmOverloads - fun shouldBlockInteraction(slot: Slot?, action: SlotActionType, itemStackOverride: ItemStack? = null): Boolean { - if (slot == null && itemStackOverride == null) return false - val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride) - publish(event) - if (event.isProtected && !event.silent) { - MC.player?.sendMessage(Text.translatable("firmament.protectitem").append(event.itemStack.name)) - CommonSoundEffects.playFailure() - } - return event.isProtected - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ItemTooltipEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ItemTooltipEvent.kt deleted file mode 100644 index d86e06f..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ItemTooltipEvent.kt +++ /dev/null @@ -1,14 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.item.Item.TooltipContext -import net.minecraft.item.ItemStack -import net.minecraft.item.tooltip.TooltipType -import net.minecraft.text.Text - -data class ItemTooltipEvent( - val stack: ItemStack, val context: TooltipContext, val type: TooltipType, val lines: MutableList<Text> -) : FirmamentEvent() { - companion object : FirmamentEventBus<ItemTooltipEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/MaskCommands.kt b/src/main/kotlin/moe/nea/firmament/events/MaskCommands.kt deleted file mode 100644 index 35aade0..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/MaskCommands.kt +++ /dev/null @@ -1,13 +0,0 @@ - - -package moe.nea.firmament.events - -import com.mojang.brigadier.CommandDispatcher - -data class MaskCommands(val dispatcher: CommandDispatcher<*>) : FirmamentEvent() { - companion object : FirmamentEventBus<MaskCommands>() - - fun mask(name: String) { - dispatcher.root.children.removeIf { it.name.equals(name, ignoreCase = true) } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ModifyChatEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ModifyChatEvent.kt deleted file mode 100644 index a5868e8..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ModifyChatEvent.kt +++ /dev/null @@ -1,21 +0,0 @@ - - -package moe.nea.firmament.events - -import moe.nea.firmament.util.unformattedString -import net.minecraft.text.Text - -/** - * Allow modification of a chat message before it is sent off to the user. Intended for display purposes. - */ -data class ModifyChatEvent(val originalText: Text) : FirmamentEvent() { - var unformattedString = originalText.unformattedString - private set - var replaceWith: Text = originalText - set(value) { - field = value - unformattedString = value.unformattedString - } - - companion object : FirmamentEventBus<ModifyChatEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/OutgoingPacketEvent.kt b/src/main/kotlin/moe/nea/firmament/events/OutgoingPacketEvent.kt deleted file mode 100644 index 93890ea..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/OutgoingPacketEvent.kt +++ /dev/null @@ -1,9 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.network.packet.Packet - -data class OutgoingPacketEvent(val packet: Packet<*>) : FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<OutgoingPacketEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ParticleSpawnEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ParticleSpawnEvent.kt deleted file mode 100644 index 9359e4b..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ParticleSpawnEvent.kt +++ /dev/null @@ -1,18 +0,0 @@ - - -package moe.nea.firmament.events - -import org.joml.Vector3f -import net.minecraft.particle.ParticleEffect -import net.minecraft.util.math.Vec3d - -data class ParticleSpawnEvent( - val particleEffect: ParticleEffect, - val position: Vec3d, - val offset: Vector3f, - val longDistance: Boolean, - val count: Int, - val speed: Float, -) : FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<ParticleSpawnEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/PlayerInventoryUpdate.kt b/src/main/kotlin/moe/nea/firmament/events/PlayerInventoryUpdate.kt deleted file mode 100644 index 6e8203a..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/PlayerInventoryUpdate.kt +++ /dev/null @@ -1,11 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.item.ItemStack - -sealed class PlayerInventoryUpdate : FirmamentEvent() { - companion object : FirmamentEventBus<PlayerInventoryUpdate>() - data class Single(val slot: Int, val stack: ItemStack) : PlayerInventoryUpdate() - data class Multi(val contents: List<ItemStack>) : PlayerInventoryUpdate() - -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ProcessChatEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ProcessChatEvent.kt deleted file mode 100644 index 76c0b27..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ProcessChatEvent.kt +++ /dev/null @@ -1,28 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.text.Text -import moe.nea.firmament.util.unformattedString - -/** - * Behaves like [AllowChatEvent], but is triggered even when cancelled by other mods. Intended for data collection. - * Make sure to subscribe to cancellable events as well when using. - */ -data class ProcessChatEvent(val text: Text, val wasExternallyCancelled: Boolean) : FirmamentEvent.Cancellable() { - val unformattedString = text.unformattedString - - val nameHeuristic: String? = run { - val firstColon = unformattedString.indexOf(':') - if (firstColon < 0) return@run null - val firstSpace = unformattedString.lastIndexOf(' ', firstColon) - unformattedString.substring(firstSpace + 1 until firstColon).takeIf { it.isNotEmpty() } - } - - init { - if (wasExternallyCancelled) - cancelled = true - } - - companion object : FirmamentEventBus<ProcessChatEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ReloadRegistrationEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ReloadRegistrationEvent.kt deleted file mode 100644 index 4c3083e..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ReloadRegistrationEvent.kt +++ /dev/null @@ -1,7 +0,0 @@ -package moe.nea.firmament.events - -import io.github.moulberry.repo.NEURepository - -data class ReloadRegistrationEvent(val repo: NEURepository) : FirmamentEvent() { - companion object : FirmamentEventBus<ReloadRegistrationEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ScreenChangeEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ScreenChangeEvent.kt deleted file mode 100644 index 489e487..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ScreenChangeEvent.kt +++ /dev/null @@ -1,10 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.screen.Screen - -data class ScreenChangeEvent(val old: Screen?, val new: Screen?) : FirmamentEvent.Cancellable() { - var overrideScreen: Screen? = null - companion object : FirmamentEventBus<ScreenChangeEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ScreenRenderPostEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ScreenRenderPostEvent.kt deleted file mode 100644 index 79f4913..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ScreenRenderPostEvent.kt +++ /dev/null @@ -1,16 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.screen.Screen - -data class ScreenRenderPostEvent( - val screen: Screen, - val mouseX: Int, - val mouseY: Int, - val tickDelta: Float, - val drawContext: DrawContext -) : FirmamentEvent() { - companion object : FirmamentEventBus<ScreenRenderPostEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/ServerConnectedEvent.kt b/src/main/kotlin/moe/nea/firmament/events/ServerConnectedEvent.kt deleted file mode 100644 index 26897f2..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/ServerConnectedEvent.kt +++ /dev/null @@ -1,18 +0,0 @@ -package moe.nea.firmament.events - -import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents -import net.minecraft.client.MinecraftClient -import net.minecraft.client.network.ClientPlayNetworkHandler -import net.minecraft.network.ClientConnection - -data class ServerConnectedEvent( - val connection: ClientConnection -) : FirmamentEvent() { - companion object : FirmamentEventBus<ServerConnectedEvent>() { - init { - ClientPlayConnectionEvents.INIT.register(ClientPlayConnectionEvents.Init { clientPlayNetworkHandler: ClientPlayNetworkHandler, minecraftClient: MinecraftClient -> - publishSync(ServerConnectedEvent(clientPlayNetworkHandler.connection)) - }) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/SkyblockServerUpdateEvent.kt b/src/main/kotlin/moe/nea/firmament/events/SkyblockServerUpdateEvent.kt deleted file mode 100644 index 0bc5143..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/SkyblockServerUpdateEvent.kt +++ /dev/null @@ -1,15 +0,0 @@ - - -package moe.nea.firmament.events - -import moe.nea.firmament.util.Locraw - -/** - * This event gets published whenever `/locraw` is queried and HyPixel returns a location different to the old one. - * - * **N.B.:** This event may get fired multiple times while on the server (for example, first to null, then to the - * correct location). - */ -data class SkyblockServerUpdateEvent(val oldLocraw: Locraw?, val newLocraw: Locraw?) : FirmamentEvent() { - companion object : FirmamentEventBus<SkyblockServerUpdateEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/SlotClickEvent.kt b/src/main/kotlin/moe/nea/firmament/events/SlotClickEvent.kt deleted file mode 100644 index d4abfb0..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/SlotClickEvent.kt +++ /dev/null @@ -1,15 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.item.ItemStack -import net.minecraft.screen.slot.Slot -import net.minecraft.screen.slot.SlotActionType - -data class SlotClickEvent( - val slot: Slot, - val stack: ItemStack, - val button: Int, - val actionType: SlotActionType, -) : FirmamentEvent() { - companion object : FirmamentEventBus<SlotClickEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/SlotRenderEvents.kt b/src/main/kotlin/moe/nea/firmament/events/SlotRenderEvents.kt deleted file mode 100644 index 8352581..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/SlotRenderEvents.kt +++ /dev/null @@ -1,34 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.DrawContext -import net.minecraft.screen.slot.Slot - -interface SlotRenderEvents { - val context: DrawContext - val slot: Slot - val mouseX: Int - val mouseY: Int - val delta: Float - - data class Before( - override val context: DrawContext, override val slot: Slot, - override val mouseX: Int, - override val mouseY: Int, - override val delta: Float - ) : FirmamentEvent(), - SlotRenderEvents { - companion object : FirmamentEventBus<Before>() - } - - data class After( - override val context: DrawContext, override val slot: Slot, - override val mouseX: Int, - override val mouseY: Int, - override val delta: Float - ) : FirmamentEvent(), - SlotRenderEvents { - companion object : FirmamentEventBus<After>() - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/SoundReceiveEvent.kt b/src/main/kotlin/moe/nea/firmament/events/SoundReceiveEvent.kt deleted file mode 100644 index d1b85b6..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/SoundReceiveEvent.kt +++ /dev/null @@ -1,18 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.registry.entry.RegistryEntry -import net.minecraft.sound.SoundCategory -import net.minecraft.sound.SoundEvent -import net.minecraft.util.math.Vec3d - -data class SoundReceiveEvent( - val sound: RegistryEntry<SoundEvent>, - val category: SoundCategory, - val position: Vec3d, - val pitch: Float, - val volume: Float, - val seed: Long -) : FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<SoundReceiveEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/TickEvent.kt b/src/main/kotlin/moe/nea/firmament/events/TickEvent.kt deleted file mode 100644 index 18007f8..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/TickEvent.kt +++ /dev/null @@ -1,7 +0,0 @@ - - -package moe.nea.firmament.events - -data class TickEvent(val tickCount: Int) : FirmamentEvent() { - companion object : FirmamentEventBus<TickEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/TooltipEvent.kt b/src/main/kotlin/moe/nea/firmament/events/TooltipEvent.kt deleted file mode 100644 index 630ba56..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/TooltipEvent.kt +++ /dev/null @@ -1,17 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.gui.tooltip.Tooltip -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.item.Item -import net.minecraft.item.ItemStack - -data class TooltipEvent( - val itemStack: ItemStack, - val tooltip: Tooltip, - val tooltipContext: Item.TooltipContext, - val player: PlayerEntity? -) : FirmamentEvent() { - companion object : FirmamentEventBus<TooltipEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/UseBlockEvent.kt b/src/main/kotlin/moe/nea/firmament/events/UseBlockEvent.kt deleted file mode 100644 index 8bbe0de..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/UseBlockEvent.kt +++ /dev/null @@ -1,11 +0,0 @@ - -package moe.nea.firmament.events - -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.util.Hand -import net.minecraft.util.hit.BlockHitResult -import net.minecraft.world.World - -data class UseBlockEvent(val player: PlayerEntity, val world: World, val hand: Hand, val hitResult: BlockHitResult) : FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<UseBlockEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/WorldKeyboardEvent.kt b/src/main/kotlin/moe/nea/firmament/events/WorldKeyboardEvent.kt deleted file mode 100644 index e8566fd..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/WorldKeyboardEvent.kt +++ /dev/null @@ -1,18 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.option.KeyBinding -import moe.nea.firmament.keybindings.IKeyBinding - -data class WorldKeyboardEvent(val keyCode: Int, val scanCode: Int, val modifiers: Int) : FirmamentEvent.Cancellable() { - companion object : FirmamentEventBus<WorldKeyboardEvent>() - - fun matches(keyBinding: KeyBinding): Boolean { - return matches(IKeyBinding.minecraft(keyBinding)) - } - - fun matches(keyBinding: IKeyBinding): Boolean { - return keyBinding.matches(keyCode, scanCode, modifiers) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/events/WorldReadyEvent.kt b/src/main/kotlin/moe/nea/firmament/events/WorldReadyEvent.kt deleted file mode 100644 index 2c76c44..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/WorldReadyEvent.kt +++ /dev/null @@ -1,7 +0,0 @@ - - -package moe.nea.firmament.events - -class WorldReadyEvent : FirmamentEvent() { - companion object : FirmamentEventBus<WorldReadyEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/WorldRenderLastEvent.kt b/src/main/kotlin/moe/nea/firmament/events/WorldRenderLastEvent.kt deleted file mode 100644 index 21a670d..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/WorldRenderLastEvent.kt +++ /dev/null @@ -1,27 +0,0 @@ - - -package moe.nea.firmament.events - -import net.minecraft.client.render.Camera -import net.minecraft.client.render.GameRenderer -import net.minecraft.client.render.LightmapTextureManager -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.util.math.Position -import net.minecraft.util.math.Vec3d - -/** - * This event is called after all world rendering is done, but before any GUI rendering (including hand) has been done. - */ -data class WorldRenderLastEvent( - val matrices: MatrixStack, - val tickCounter: RenderTickCounter, - val renderBlockOutline: Boolean, - val camera: Camera, - val gameRenderer: GameRenderer, - val lightmapTextureManager: LightmapTextureManager, - val vertexConsumers: VertexConsumerProvider.Immediate, -) : FirmamentEvent() { - companion object : FirmamentEventBus<WorldRenderLastEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/events/registration/ChatEvents.kt b/src/main/kotlin/moe/nea/firmament/events/registration/ChatEvents.kt deleted file mode 100644 index 4c1c63f..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/registration/ChatEvents.kt +++ /dev/null @@ -1,54 +0,0 @@ - - -package moe.nea.firmament.events.registration - -import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents -import net.fabricmc.fabric.api.event.player.AttackBlockCallback -import net.fabricmc.fabric.api.event.player.UseBlockCallback -import net.minecraft.text.Text -import net.minecraft.util.ActionResult -import moe.nea.firmament.events.AllowChatEvent -import moe.nea.firmament.events.AttackBlockEvent -import moe.nea.firmament.events.ModifyChatEvent -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.UseBlockEvent - -private var lastReceivedMessage: Text? = null - -fun registerFirmamentEvents() { - ClientReceiveMessageEvents.ALLOW_CHAT.register(ClientReceiveMessageEvents.AllowChat { message, signedMessage, sender, params, receptionTimestamp -> - lastReceivedMessage = message - !ProcessChatEvent.publish(ProcessChatEvent(message, false)).cancelled - && !AllowChatEvent.publish(AllowChatEvent(message)).cancelled - }) - ClientReceiveMessageEvents.ALLOW_GAME.register(ClientReceiveMessageEvents.AllowGame { message, overlay -> - lastReceivedMessage = message - overlay || (!ProcessChatEvent.publish(ProcessChatEvent(message, false)).cancelled && - !AllowChatEvent.publish(AllowChatEvent(message)).cancelled) - }) - ClientReceiveMessageEvents.MODIFY_GAME.register(ClientReceiveMessageEvents.ModifyGame { message, overlay -> - if (overlay) message - else ModifyChatEvent.publish(ModifyChatEvent(message)).replaceWith - }) - ClientReceiveMessageEvents.GAME_CANCELED.register(ClientReceiveMessageEvents.GameCanceled { message, overlay -> - if (!overlay && lastReceivedMessage !== message) { - ProcessChatEvent.publish(ProcessChatEvent(message, true)) - } - }) - ClientReceiveMessageEvents.CHAT_CANCELED.register(ClientReceiveMessageEvents.ChatCanceled { message, signedMessage, sender, params, receptionTimestamp -> - if (lastReceivedMessage !== message) { - ProcessChatEvent.publish(ProcessChatEvent(message, true)) - } - }) - - AttackBlockCallback.EVENT.register(AttackBlockCallback { player, world, hand, pos, direction -> - if (AttackBlockEvent.publish(AttackBlockEvent(player, world, hand, pos, direction)).cancelled) - ActionResult.CONSUME - else ActionResult.PASS - }) - UseBlockCallback.EVENT.register(UseBlockCallback { player, world, hand, hitResult -> - if (UseBlockEvent.publish(UseBlockEvent(player, world, hand, hitResult)).cancelled) - ActionResult.CONSUME - else ActionResult.PASS - }) -} diff --git a/src/main/kotlin/moe/nea/firmament/events/subscription/Subscription.kt b/src/main/kotlin/moe/nea/firmament/events/subscription/Subscription.kt deleted file mode 100644 index 83b91c9..0000000 --- a/src/main/kotlin/moe/nea/firmament/events/subscription/Subscription.kt +++ /dev/null @@ -1,16 +0,0 @@ - -package moe.nea.firmament.events.subscription - -import moe.nea.firmament.events.FirmamentEvent -import moe.nea.firmament.events.FirmamentEventBus -import moe.nea.firmament.features.FirmamentFeature - -interface SubscriptionOwner { - val delegateFeature: FirmamentFeature -} - -data class Subscription<T : FirmamentEvent>( - val owner: Any, - val invoke: (T) -> Unit, - val eventBus: FirmamentEventBus<T>, -) diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt deleted file mode 100644 index 19b91de..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ /dev/null @@ -1,120 +0,0 @@ - - -package moe.nea.firmament.features - -import kotlinx.serialization.Serializable -import kotlinx.serialization.serializer -import moe.nea.firmament.Firmament -import moe.nea.firmament.annotations.generated.AllSubscriptions -import moe.nea.firmament.events.FeaturesInitializedEvent -import moe.nea.firmament.events.FirmamentEvent -import moe.nea.firmament.events.subscription.Subscription -import moe.nea.firmament.features.chat.AutoCompletions -import moe.nea.firmament.features.chat.ChatLinks -import moe.nea.firmament.features.chat.QuickCommands -import moe.nea.firmament.features.debug.DebugView -import moe.nea.firmament.features.debug.DeveloperFeatures -import moe.nea.firmament.features.debug.MinorTrolling -import moe.nea.firmament.features.debug.PowerUserTools -import moe.nea.firmament.features.diana.DianaWaypoints -import moe.nea.firmament.features.events.anniversity.AnniversaryFeatures -import moe.nea.firmament.features.events.carnival.CarnivalFeatures -import moe.nea.firmament.features.fixes.CompatibliltyFeatures -import moe.nea.firmament.features.fixes.Fixes -import moe.nea.firmament.features.inventory.CraftingOverlay -import moe.nea.firmament.features.inventory.ItemRarityCosmetics -import moe.nea.firmament.features.inventory.PriceData -import moe.nea.firmament.features.inventory.SaveCursorPosition -import moe.nea.firmament.features.inventory.SlotLocking -import moe.nea.firmament.features.inventory.buttons.InventoryButtons -import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlay -import moe.nea.firmament.features.mining.PickaxeAbility -import moe.nea.firmament.features.mining.PristineProfitTracker -import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures -import moe.nea.firmament.features.world.FairySouls -import moe.nea.firmament.features.world.Waypoints -import moe.nea.firmament.util.data.DataHolder - -object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "features", ::Config) { - @Serializable - data class Config( - val enabledFeatures: MutableMap<String, Boolean> = mutableMapOf() - ) - - private val features = mutableMapOf<String, FirmamentFeature>() - - val allFeatures: Collection<FirmamentFeature> get() = features.values - - private var hasAutoloaded = false - - init { - autoload() - } - - fun autoload() { - synchronized(this) { - if (hasAutoloaded) return - loadFeature(MinorTrolling) - loadFeature(FairySouls) - loadFeature(AutoCompletions) - // TODO: loadFeature(FishingWarning) - loadFeature(SlotLocking) - loadFeature(StorageOverlay) - loadFeature(PristineProfitTracker) - loadFeature(CraftingOverlay) - loadFeature(PowerUserTools) - loadFeature(Waypoints) - loadFeature(ChatLinks) - loadFeature(InventoryButtons) - loadFeature(CompatibliltyFeatures) - loadFeature(AnniversaryFeatures) - loadFeature(QuickCommands) - loadFeature(SaveCursorPosition) - loadFeature(CustomSkyBlockTextures) - loadFeature(PriceData) - loadFeature(Fixes) - loadFeature(DianaWaypoints) - loadFeature(ItemRarityCosmetics) - loadFeature(PickaxeAbility) - loadFeature(CarnivalFeatures) - if (Firmament.DEBUG) { - loadFeature(DeveloperFeatures) - loadFeature(DebugView) - } - allFeatures.forEach { it.config } - FeaturesInitializedEvent.publish(FeaturesInitializedEvent(allFeatures.toList())) - hasAutoloaded = true - } - } - - fun subscribeEvents() { - AllSubscriptions.provideSubscriptions { - subscribeSingleEvent(it) - } - } - - private fun <T : FirmamentEvent> subscribeSingleEvent(it: Subscription<T>) { - it.eventBus.subscribe(false, it.invoke) - } - - fun loadFeature(feature: FirmamentFeature) { - synchronized(features) { - if (feature.identifier in features) { - Firmament.logger.error("Double registering feature ${feature.identifier}. Ignoring second instance $feature") - return - } - features[feature.identifier] = feature - feature.onLoad() - } - } - - fun isEnabled(identifier: String): Boolean? = - data.enabledFeatures[identifier] - - - fun setEnabled(identifier: String, value: Boolean) { - data.enabledFeatures[identifier] = value - markDirty() - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt b/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt deleted file mode 100644 index 2cfc4fd..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/FirmamentFeature.kt +++ /dev/null @@ -1,23 +0,0 @@ - - -package moe.nea.firmament.features - -import moe.nea.firmament.events.subscription.SubscriptionOwner -import moe.nea.firmament.gui.config.ManagedConfig - -// TODO: remove this entire feature system and revamp config -interface FirmamentFeature : SubscriptionOwner { - val identifier: String - val defaultEnabled: Boolean - get() = true - var isEnabled: Boolean - get() = FeatureManager.isEnabled(identifier) ?: defaultEnabled - set(value) { - FeatureManager.setEnabled(identifier, value) - } - override val delegateFeature: FirmamentFeature - get() = this - val config: ManagedConfig? get() = null - fun onLoad() {} - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/chat/AutoCompletions.kt b/src/main/kotlin/moe/nea/firmament/features/chat/AutoCompletions.kt deleted file mode 100644 index 9144898..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/chat/AutoCompletions.kt +++ /dev/null @@ -1,57 +0,0 @@ - - -package moe.nea.firmament.features.chat - -import com.mojang.brigadier.arguments.StringArgumentType.string -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.commands.get -import moe.nea.firmament.commands.suggestsList -import moe.nea.firmament.commands.thenArgument -import moe.nea.firmament.commands.thenExecute -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.events.MaskCommands -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.MC - -object AutoCompletions : FirmamentFeature { - - object TConfig : ManagedConfig(identifier) { - val provideWarpTabCompletion by toggle("warp-complete") { true } - val replaceWarpIsByWarpIsland by toggle("warp-is") { true } - } - - override val config: ManagedConfig? - get() = TConfig - override val identifier: String - get() = "auto-completions" - - @Subscribe - fun onMaskCommands(event: MaskCommands) { - if (TConfig.provideWarpTabCompletion) { - event.mask("warp") - } - } - - @Subscribe - fun onCommandEvent(event: CommandEvent) { - if (!TConfig.provideWarpTabCompletion) return - event.deleteCommand("warp") - event.register("warp") { - thenArgument("to", string()) { toArg -> - suggestsList { - RepoManager.neuRepo.constants?.islands?.warps?.flatMap { listOf(it.warp) + it.aliases } ?: listOf() - } - thenExecute { - val warpName = get(toArg) - if (warpName == "is" && TConfig.replaceWarpIsByWarpIsland) { - MC.sendServerCommand("warp island") - } else { - MC.sendServerCommand("warp $warpName") - } - } - } - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/chat/ChatLinks.kt b/src/main/kotlin/moe/nea/firmament/features/chat/ChatLinks.kt deleted file mode 100644 index f2cb78a..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/chat/ChatLinks.kt +++ /dev/null @@ -1,161 +0,0 @@ - - -package moe.nea.firmament.features.chat - -import io.ktor.client.request.get -import io.ktor.client.statement.bodyAsChannel -import io.ktor.utils.io.jvm.javaio.toInputStream -import java.net.URL -import java.util.Collections -import moe.nea.jarvis.api.Point -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.async -import kotlin.math.min -import net.minecraft.client.gui.screen.ChatScreen -import net.minecraft.client.texture.NativeImage -import net.minecraft.client.texture.NativeImageBackedTexture -import net.minecraft.text.ClickEvent -import net.minecraft.text.HoverEvent -import net.minecraft.text.Style -import net.minecraft.text.Text -import net.minecraft.util.Formatting -import net.minecraft.util.Identifier -import moe.nea.firmament.Firmament -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ModifyChatEvent -import moe.nea.firmament.events.ScreenRenderPostEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.transformEachRecursively -import moe.nea.firmament.util.unformattedString - -object ChatLinks : FirmamentFeature { - override val identifier: String - get() = "chat-links" - - object TConfig : ManagedConfig(identifier) { - val enableLinks by toggle("links-enabled") { true } - val imageEnabled by toggle("image-enabled") { true } - val allowAllHosts by toggle("allow-all-hosts") { false } - val allowedHosts by string("allowed-hosts") { "cdn.discordapp.com,media.discordapp.com,media.discordapp.net,i.imgur.com" } - val actualAllowedHosts get() = allowedHosts.split(",").map { it.trim() } - val position by position("position", 16 * 20, 9 * 20) { Point(0.0, 0.0) } - } - - private fun isHostAllowed(host: String) = - TConfig.allowAllHosts || TConfig.actualAllowedHosts.any { it.equals(host, ignoreCase = true) } - - private fun isUrlAllowed(url: String) = isHostAllowed(url.removePrefix("https://").substringBefore("/")) - - override val config get() = TConfig - val urlRegex = "https://[^. ]+\\.[^ ]+(\\.?( |$))".toRegex() - - data class Image( - val texture: Identifier, - val width: Int, - val height: Int, - ) - - val imageCache: MutableMap<String, Deferred<Image?>> = - Collections.synchronizedMap(mutableMapOf<String, Deferred<Image?>>()) - - private fun tryCacheUrl(url: String) { - if (!isUrlAllowed(url)) { - return - } - if (url in imageCache) { - return - } - imageCache[url] = Firmament.coroutineScope.async { - try { - val response = Firmament.httpClient.get(URL(url)) - if (response.status.value == 200) { - val inputStream = response.bodyAsChannel().toInputStream(Firmament.globalJob) - val image = NativeImage.read(inputStream) - val texture = MC.textureManager.registerDynamicTexture( - "dynamic_image_preview", - NativeImageBackedTexture(image) - ) - Image(texture, image.width, image.height) - } else - null - } catch (exc: Exception) { - exc.printStackTrace() - null - } - } - } - - val imageExtensions = listOf("jpg", "png", "gif", "jpeg") - fun isImageUrl(url: String): Boolean { - return (url.substringAfterLast('.').lowercase() in imageExtensions) - } - - @Subscribe - @OptIn(ExperimentalCoroutinesApi::class) - fun onRender(it: ScreenRenderPostEvent) { - if (!TConfig.imageEnabled) return - if (it.screen !is ChatScreen) return - val hoveredComponent = - MC.inGameHud.chatHud.getTextStyleAt(it.mouseX.toDouble(), it.mouseY.toDouble()) ?: return - val hoverEvent = hoveredComponent.hoverEvent ?: return - val value = hoverEvent.getValue(HoverEvent.Action.SHOW_TEXT) ?: return - val url = urlRegex.matchEntire(value.unformattedString)?.groupValues?.get(0) ?: return - if (!isImageUrl(url)) return - val imageFuture = imageCache[url] ?: return - if (!imageFuture.isCompleted) return - val image = imageFuture.getCompleted() ?: return - it.drawContext.matrices.push() - val pos = TConfig.position - pos.applyTransformations(it.drawContext.matrices) - val scale = min(1F, min((9 * 20F) / image.height, (16 * 20F) / image.width)) - it.drawContext.matrices.scale(scale, scale, 1F) - it.drawContext.drawTexture( - image.texture, - 0, - 0, - 1F, - 1F, - image.width, - image.height, - image.width, - image.height, - ) - it.drawContext.matrices.pop() - } - - @Subscribe - fun onModifyChat(it: ModifyChatEvent) { - if (!TConfig.enableLinks) return - it.replaceWith = it.replaceWith.transformEachRecursively { child -> - val text = child.string - if ("://" !in text) return@transformEachRecursively child - val s = Text.empty().setStyle(child.style) - var index = 0 - while (index < text.length) { - val nextMatch = urlRegex.find(text, index) - if (nextMatch == null) { - s.append(Text.literal(text.substring(index, text.length))) - break - } - val range = nextMatch.groups[0]!!.range - val url = nextMatch.groupValues[0] - s.append(Text.literal(text.substring(index, range.first))) - s.append( - Text.literal(url).setStyle( - Style.EMPTY.withUnderline(true).withColor( - Formatting.AQUA - ).withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.literal(url))) - .withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, url)) - ) - ) - if (isImageUrl(url)) - tryCacheUrl(url) - index = range.last + 1 - } - s - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/chat/QuickCommands.kt b/src/main/kotlin/moe/nea/firmament/features/chat/QuickCommands.kt deleted file mode 100644 index 5944b92..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/chat/QuickCommands.kt +++ /dev/null @@ -1,100 +0,0 @@ - - -package moe.nea.firmament.features.chat - -import com.mojang.brigadier.context.CommandContext -import net.minecraft.text.Text -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.commands.DefaultSource -import moe.nea.firmament.commands.RestArgumentType -import moe.nea.firmament.commands.get -import moe.nea.firmament.commands.thenArgument -import moe.nea.firmament.commands.thenExecute -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SBData - -object QuickCommands : FirmamentFeature { - override val identifier: String - get() = "quick-commands" - - fun removePartialPrefix(text: String, prefix: String): String? { - var lf: String? = null - for (i in 1..prefix.length) { - if (text.startsWith(prefix.substring(0, i))) { - lf = text.substring(i) - } - } - return lf - } - - val kuudraLevelNames = listOf("NORMAL", "HOT", "BURNING", "FIERY", "INFERNAL") - val dungeonLevelNames = listOf("ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN") - - @Subscribe - fun onCommands(it: CommandEvent) { - it.register("join") { - thenArgument("what", RestArgumentType) { what -> - thenExecute { - val what = this[what] - if (!SBData.isOnSkyblock) { - MC.sendCommand("join $what") - return@thenExecute - } - val joinName = getNameForFloor(what.replace(" ", "").lowercase()) - if (joinName == null) { - source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown", what)) - } else { - source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.success", - joinName)) - MC.sendCommand("joininstance $joinName") - } - } - } - thenExecute { - source.sendFeedback(Text.translatable("firmament.quick-commands.join.explain")) - } - } - } - - fun CommandContext<DefaultSource>.getNameForFloor(w: String): String? { - val kuudraLevel = removePartialPrefix(w, "kuudratier") ?: removePartialPrefix(w, "tier") - if (kuudraLevel != null) { - val l = kuudraLevel.toIntOrNull()?.let { it - 1 } ?: kuudraLevelNames.indexOfFirst { - it.startsWith( - kuudraLevel, - true - ) - } - if (l !in kuudraLevelNames.indices) { - source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-kuudra", - kuudraLevel)) - return null - } - return "KUUDRA_${kuudraLevelNames[l]}" - } - val masterLevel = removePartialPrefix(w, "master") - val normalLevel = - removePartialPrefix(w, "floor") ?: removePartialPrefix(w, "catacombs") ?: removePartialPrefix(w, "dungeons") - val dungeonLevel = masterLevel ?: normalLevel - if (dungeonLevel != null) { - val l = dungeonLevel.toIntOrNull()?.let { it - 1 } ?: dungeonLevelNames.indexOfFirst { - it.startsWith( - dungeonLevel, - true - ) - } - if (masterLevel == null && (l == -1 || null != removePartialPrefix(w, "entrance"))) { - return "CATACOMBS_ENTRANCE" - } - if (l !in dungeonLevelNames.indices) { - source.sendFeedback(Text.stringifiedTranslatable("firmament.quick-commands.join.unknown-catacombs", - kuudraLevel)) - return null - } - return "${if (masterLevel != null) "MASTER_" else ""}CATACOMBS_FLOOR_${dungeonLevelNames[l]}" - } - return null - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/DebugLogger.kt b/src/main/kotlin/moe/nea/firmament/features/debug/DebugLogger.kt deleted file mode 100644 index ab06030..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/debug/DebugLogger.kt +++ /dev/null @@ -1,13 +0,0 @@ - -package moe.nea.firmament.features.debug - -import net.minecraft.text.Text -import moe.nea.firmament.util.MC - -class DebugLogger(val tag: String) { - fun isEnabled() = DeveloperFeatures.isEnabled // TODO: allow filtering by tag - fun log(text: () -> String) { - if (!isEnabled()) return - MC.sendChat(Text.literal(text())) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/DebugView.kt b/src/main/kotlin/moe/nea/firmament/features/debug/DebugView.kt deleted file mode 100644 index 7e1b8ec..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/debug/DebugView.kt +++ /dev/null @@ -1,38 +0,0 @@ - - -package moe.nea.firmament.features.debug - -import moe.nea.firmament.Firmament -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.util.TimeMark - -object DebugView : FirmamentFeature { - private data class StoredVariable<T>( - val obj: T, - val timer: TimeMark, - ) - - private val storedVariables: MutableMap<String, StoredVariable<*>> = sortedMapOf() - override val identifier: String - get() = "debug-view" - override val defaultEnabled: Boolean - get() = Firmament.DEBUG - - fun <T : Any?> showVariable(label: String, obj: T) { - synchronized(this) { - storedVariables[label] = StoredVariable(obj, TimeMark.now()) - } - } - - fun recalculateDebugWidget() { - } - - override fun onLoad() { - TickEvent.subscribe { - synchronized(this) { - recalculateDebugWidget() - } - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt deleted file mode 100644 index 20c0cfd..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/debug/DeveloperFeatures.kt +++ /dev/null @@ -1,55 +0,0 @@ - - -package moe.nea.firmament.features.debug - -import java.nio.file.Path -import java.util.concurrent.CompletableFuture -import kotlin.io.path.absolute -import kotlin.io.path.exists -import net.minecraft.client.MinecraftClient -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.TimeMark -import moe.nea.firmament.util.errorBoundary -import moe.nea.firmament.util.iterate - -object DeveloperFeatures : FirmamentFeature { - override val identifier: String - get() = "developer" - override val config: TConfig - get() = TConfig - override val defaultEnabled: Boolean - get() = Firmament.DEBUG - - val gradleDir = - Path.of(".").absolute() - .iterate { it.parent } - .find { it.resolve("settings.gradle.kts").exists() } - - object TConfig : ManagedConfig("developer") { - val autoRebuildResources by toggle("auto-rebuild") { false } - } - - @JvmStatic - fun hookOnBeforeResourceReload(client: MinecraftClient): CompletableFuture<Void> { - val reloadFuture = if (TConfig.autoRebuildResources && isEnabled && gradleDir != null) { - val builder = ProcessBuilder("./gradlew", ":processResources") - builder.directory(gradleDir.toFile()) - builder.inheritIO() - val process = builder.start() - MC.player?.sendMessage(Text.translatable("firmament.dev.resourcerebuild.start")) - val startTime = TimeMark.now() - process.toHandle().onExit().thenApply { - MC.player?.sendMessage(Text.stringifiedTranslatable("firmament.dev.resourcerebuild.done", startTime.passedTime())) - Unit - } - } else { - CompletableFuture.completedFuture(Unit) - } - return reloadFuture.thenCompose { client.reloadResources() } - } -} - diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/MinorTrolling.kt b/src/main/kotlin/moe/nea/firmament/features/debug/MinorTrolling.kt deleted file mode 100644 index 32035a6..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/debug/MinorTrolling.kt +++ /dev/null @@ -1,27 +0,0 @@ - - -package moe.nea.firmament.features.debug - -import net.minecraft.text.Text -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ModifyChatEvent -import moe.nea.firmament.features.FirmamentFeature - - -// In memorian Dulkir -object MinorTrolling : FirmamentFeature { - override val identifier: String - get() = "minor-trolling" - - val trollers = listOf("nea89o", "lrg89") - val t = "From(?: \\[[^\\]]+])? ([^:]+): (.*)".toRegex() - - @Subscribe - fun onTroll(it: ModifyChatEvent) { - val m = t.matchEntire(it.unformattedString) ?: return - val (_, name, text) = m.groupValues - if (name !in trollers) return - if (!text.startsWith("c:")) return - it.replaceWith = Text.literal(text.substring(2).replace("&", "§")) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt b/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt deleted file mode 100644 index 7893eff..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt +++ /dev/null @@ -1,193 +0,0 @@ - - -package moe.nea.firmament.features.debug - -import net.minecraft.block.SkullBlock -import net.minecraft.block.entity.SkullBlockEntity -import net.minecraft.component.DataComponentTypes -import net.minecraft.entity.Entity -import net.minecraft.entity.LivingEntity -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import net.minecraft.text.Text -import net.minecraft.util.hit.BlockHitResult -import net.minecraft.util.hit.EntityHitResult -import net.minecraft.util.hit.HitResult -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.events.CustomItemModelEvent -import moe.nea.firmament.events.HandledScreenKeyPressedEvent -import moe.nea.firmament.events.ItemTooltipEvent -import moe.nea.firmament.events.ScreenChangeEvent -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.events.WorldKeyboardEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.mixins.accessor.AccessorHandledScreen -import moe.nea.firmament.util.ClipboardUtils -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.focusedItemStack -import moe.nea.firmament.util.skyBlockId - -object PowerUserTools : FirmamentFeature { - override val identifier: String - get() = "power-user" - - object TConfig : ManagedConfig(identifier) { - val showItemIds by toggle("show-item-id") { false } - val copyItemId by keyBindingWithDefaultUnbound("copy-item-id") - val copyTexturePackId by keyBindingWithDefaultUnbound("copy-texture-pack-id") - val copyNbtData by keyBindingWithDefaultUnbound("copy-nbt-data") - val copySkullTexture by keyBindingWithDefaultUnbound("copy-skull-texture") - val copyEntityData by keyBindingWithDefaultUnbound("entity-data") - } - - override val config - get() = TConfig - - var lastCopiedStack: Pair<ItemStack, Text>? = null - set(value) { - field = value - if (value != null) - lastCopiedStackViewTime = true - } - var lastCopiedStackViewTime = false - - override fun onLoad() { - TickEvent.subscribe { - if (!lastCopiedStackViewTime) - lastCopiedStack = null - lastCopiedStackViewTime = false - } - ScreenChangeEvent.subscribe { - lastCopiedStack = null - } - } - - fun debugFormat(itemStack: ItemStack): Text { - return Text.literal(itemStack.skyBlockId?.toString() ?: itemStack.toString()) - } - - @Subscribe - fun onEntityInfo(event: WorldKeyboardEvent) { - if (!event.matches(TConfig.copyEntityData)) return - val target = (MC.instance.crosshairTarget as? EntityHitResult)?.entity - if (target == null) { - MC.sendChat(Text.translatable("firmament.poweruser.entity.fail")) - return - } - showEntity(target) - } - - fun showEntity(target: Entity) { - MC.sendChat(Text.translatable("firmament.poweruser.entity.type", target.type)) - MC.sendChat(Text.translatable("firmament.poweruser.entity.name", target.name)) - MC.sendChat(Text.stringifiedTranslatable("firmament.poweruser.entity.position", target.pos)) - if (target is LivingEntity) { - MC.sendChat(Text.translatable("firmament.poweruser.entity.armor")) - for (armorItem in target.armorItems) { - MC.sendChat(Text.translatable("firmament.poweruser.entity.armor.item", debugFormat(armorItem))) - } - } - MC.sendChat(Text.stringifiedTranslatable("firmament.poweruser.entity.passengers", target.passengerList.size)) - target.passengerList.forEach { - showEntity(it) - } - } - - - @Subscribe - fun copyInventoryInfo(it: HandledScreenKeyPressedEvent) { - if (it.screen !is AccessorHandledScreen) return - val item = it.screen.focusedItemStack ?: return - if (it.matches(TConfig.copyItemId)) { - val sbId = item.skyBlockId - if (sbId == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skyblockid.fail")) - return - } - ClipboardUtils.setTextContent(sbId.neuItem) - lastCopiedStack = - Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skyblockid", sbId.neuItem)) - } else if (it.matches(TConfig.copyTexturePackId)) { - val model = CustomItemModelEvent.getModelIdentifier(item) - if (model == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.modelid.fail")) - return - } - ClipboardUtils.setTextContent(model.toString()) - lastCopiedStack = - Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.modelid", model.toString())) - } else if (it.matches(TConfig.copyNbtData)) { - // TODO: copy full nbt - val nbt = item.get(DataComponentTypes.CUSTOM_DATA)?.nbt?.toString() ?: "<empty>" - ClipboardUtils.setTextContent(nbt) - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.nbt")) - } else if (it.matches(TConfig.copySkullTexture)) { - if (item.item != Items.PLAYER_HEAD) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-skull")) - return - } - val profile = item.get(DataComponentTypes.PROFILE) - if (profile == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-profile")) - return - } - val skullTexture = CustomSkyBlockTextures.getSkullTexture(profile) - if (skullTexture == null) { - lastCopiedStack = Pair(item, Text.translatable("firmament.tooltip.copied.skull-id.fail.no-texture")) - return - } - ClipboardUtils.setTextContent(skullTexture.toString()) - lastCopiedStack = - Pair( - item, - Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString()) - ) - println("Copied skull id: $skullTexture") - } - } - - @Subscribe - fun onCopyWorldInfo(it: WorldKeyboardEvent) { - if (it.matches(TConfig.copySkullTexture)) { - val p = MC.camera ?: return - val blockHit = p.raycast(20.0, 0.0f, false) ?: return - if (blockHit.type != HitResult.Type.BLOCK || blockHit !is BlockHitResult) { - MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) - return - } - val blockAt = p.world.getBlockState(blockHit.blockPos)?.block - val entity = p.world.getBlockEntity(blockHit.blockPos) - if (blockAt !is SkullBlock || entity !is SkullBlockEntity || entity.owner == null) { - MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) - return - } - val id = CustomSkyBlockTextures.getSkullTexture(entity.owner!!) - if (id == null) { - MC.sendChat(Text.translatable("firmament.tooltip.copied.skull.fail")) - } else { - ClipboardUtils.setTextContent(id.toString()) - MC.sendChat(Text.stringifiedTranslatable("firmament.tooltip.copied.skull", id.toString())) - } - } - } - - @Subscribe - fun addItemId(it: ItemTooltipEvent) { - if (TConfig.showItemIds) { - val id = it.stack.skyBlockId ?: return - it.lines.add(Text.stringifiedTranslatable("firmament.tooltip.skyblockid", id.neuItem)) - } - val (item, text) = lastCopiedStack ?: return - if (!ItemStack.areEqual(item, it.stack)) { - lastCopiedStack = null - return - } - lastCopiedStackViewTime = true - it.lines.add(text) - } - - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt b/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt deleted file mode 100644 index 39ca6d3..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt +++ /dev/null @@ -1,131 +0,0 @@ - -package moe.nea.firmament.features.diana - -import kotlin.time.Duration.Companion.seconds -import net.minecraft.particle.ParticleTypes -import net.minecraft.sound.SoundEvents -import net.minecraft.util.math.Vec3d -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ParticleSpawnEvent -import moe.nea.firmament.events.SoundReceiveEvent -import moe.nea.firmament.events.WorldKeyboardEvent -import moe.nea.firmament.events.WorldReadyEvent -import moe.nea.firmament.events.WorldRenderLastEvent -import moe.nea.firmament.events.subscription.SubscriptionOwner -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SBData -import moe.nea.firmament.util.SkyBlockIsland -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.TimeMark -import moe.nea.firmament.util.WarpUtil -import moe.nea.firmament.util.render.RenderInWorldContext -import moe.nea.firmament.util.skyBlockId - -object AncestralSpadeSolver : SubscriptionOwner { - var lastDing = TimeMark.farPast() - private set - private val pitches = mutableListOf<Float>() - val particlePositions = mutableListOf<Vec3d>() - var nextGuess: Vec3d? = null - private set - - val ancestralSpadeId = SkyblockId("ANCESTRAL_SPADE") - private var lastTeleportAttempt = TimeMark.farPast() - - fun isEnabled() = - DianaWaypoints.TConfig.ancestralSpadeSolver - && SBData.skyblockLocation == SkyBlockIsland.HUB - && MC.player?.inventory?.containsAny { it.skyBlockId == ancestralSpadeId } == true // TODO: add a reactive property here - - @Subscribe - fun onKeyBind(event: WorldKeyboardEvent) { - if (!isEnabled()) return - if (!event.matches(DianaWaypoints.TConfig.ancestralSpadeTeleport)) return - - if (lastTeleportAttempt.passedTime() < 3.seconds) return - WarpUtil.teleportToNearestWarp(SkyBlockIsland.HUB, nextGuess ?: return) - lastTeleportAttempt = TimeMark.now() - } - - @Subscribe - fun onParticleSpawn(event: ParticleSpawnEvent) { - if (!isEnabled()) return - if (event.particleEffect != ParticleTypes.DRIPPING_LAVA) return - if (event.offset.x != 0.0F || event.offset.y != 0F || event.offset.z != 0F) - return - particlePositions.add(event.position) - if (particlePositions.size > 20) { - particlePositions.removeFirst() - } - } - - @Subscribe - fun onPlaySound(event: SoundReceiveEvent) { - if (!isEnabled()) return - if (!SoundEvents.BLOCK_NOTE_BLOCK_HARP.matchesId(event.sound.value().id)) return - - if (lastDing.passedTime() > 1.seconds) { - particlePositions.clear() - pitches.clear() - } - lastDing = TimeMark.now() - - pitches.add(event.pitch) - if (pitches.size > 20) { - pitches.removeFirst() - } - - if (particlePositions.size < 3) { - return - } - - val averagePitchDelta = - if (pitches.isEmpty()) return - else pitches - .zipWithNext { a, b -> b - a } - .average() - - val soundDistanceEstimate = (Math.E / averagePitchDelta) - particlePositions.first().distanceTo(event.position) - - if (soundDistanceEstimate > 1000) { - return - } - - val lastParticleDirection = particlePositions - .takeLast(3) - .let { (a, _, b) -> b.subtract(a) } - .normalize() - - nextGuess = event.position.add(lastParticleDirection.multiply(soundDistanceEstimate)) - } - - @Subscribe - fun onWorldRender(event: WorldRenderLastEvent) { - if (!isEnabled()) return - RenderInWorldContext.renderInWorld(event) { - nextGuess?.let { - color(1f, 1f, 0f, 0.5f) - tinyBlock(it, 1f) - color(1f, 1f, 0f, 1f) - tracer(it, lineWidth = 3f) - } - if (particlePositions.size > 2 && lastDing.passedTime() < 10.seconds && nextGuess != null) { - color(0f, 1f, 0f, 0.7f) - line(particlePositions) - } - } - } - - @Subscribe - fun onSwapWorld(event: WorldReadyEvent) { - nextGuess = null - particlePositions.clear() - pitches.clear() - lastDing = TimeMark.farPast() - } - - override val delegateFeature: FirmamentFeature - get() = DianaWaypoints - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt b/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt deleted file mode 100644 index 0a34eaa..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt +++ /dev/null @@ -1,35 +0,0 @@ - -package moe.nea.firmament.features.diana - -import moe.nea.firmament.events.AttackBlockEvent -import moe.nea.firmament.events.ParticleSpawnEvent -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.SoundReceiveEvent -import moe.nea.firmament.events.UseBlockEvent -import moe.nea.firmament.events.WorldKeyboardEvent -import moe.nea.firmament.events.WorldReadyEvent -import moe.nea.firmament.events.WorldRenderLastEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig - -object DianaWaypoints : FirmamentFeature { - override val identifier get() = "diana" - override val config get() = TConfig - - object TConfig : ManagedConfig(identifier) { - val ancestralSpadeSolver by toggle("ancestral-spade") { true } - val ancestralSpadeTeleport by keyBindingWithDefaultUnbound("ancestral-teleport") - val nearbyWaypoints by toggle("nearby-waypoints") { true } - } - - override fun onLoad() { - UseBlockEvent.subscribe { - NearbyBurrowsSolver.onBlockClick(it.hitResult.blockPos) - } - AttackBlockEvent.subscribe { - NearbyBurrowsSolver.onBlockClick(it.blockPos) - } - } -} - - diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/NearbyBurrowsSolver.kt b/src/main/kotlin/moe/nea/firmament/features/diana/NearbyBurrowsSolver.kt deleted file mode 100644 index 7158bb9..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/diana/NearbyBurrowsSolver.kt +++ /dev/null @@ -1,144 +0,0 @@ - -package moe.nea.firmament.features.diana - -import kotlin.time.Duration.Companion.seconds -import net.minecraft.particle.ParticleTypes -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.MathHelper -import net.minecraft.util.math.Position -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ParticleSpawnEvent -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.WorldReadyEvent -import moe.nea.firmament.events.WorldRenderLastEvent -import moe.nea.firmament.events.subscription.SubscriptionOwner -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.util.TimeMark -import moe.nea.firmament.util.mutableMapWithMaxSize -import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld - -object NearbyBurrowsSolver : SubscriptionOwner { - - - private val recentlyDugBurrows: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(20) - private val recentEnchantParticles: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(500) - private var lastBlockClick: BlockPos? = null - - enum class BurrowType { - START, MOB, TREASURE - } - - val burrows = mutableMapOf<BlockPos, BurrowType>() - - @Subscribe - fun onChatEvent(event: ProcessChatEvent) { - val lastClickedBurrow = lastBlockClick ?: return - if (event.unformattedString.startsWith("You dug out a Griffin Burrow!") || - event.unformattedString.startsWith(" ☠ You were killed by") || - event.unformattedString.startsWith("You finished the Griffin burrow chain!") - ) { - markAsDug(lastClickedBurrow) - burrows.remove(lastClickedBurrow) - } - } - - - fun wasRecentlyDug(blockPos: BlockPos): Boolean { - val lastDigTime = recentlyDugBurrows[blockPos] ?: TimeMark.farPast() - return lastDigTime.passedTime() < 10.seconds - } - - fun markAsDug(blockPos: BlockPos) { - recentlyDugBurrows[blockPos] = TimeMark.now() - } - - fun wasRecentlyEnchanted(blockPos: BlockPos): Boolean { - val lastEnchantTime = recentEnchantParticles[blockPos] ?: TimeMark.farPast() - return lastEnchantTime.passedTime() < 4.seconds - } - - fun markAsEnchanted(blockPos: BlockPos) { - recentEnchantParticles[blockPos] = TimeMark.now() - } - - @Subscribe - fun onParticles(event: ParticleSpawnEvent) { - if (!DianaWaypoints.TConfig.nearbyWaypoints) return - - val position: BlockPos = event.position.toBlockPos().down() - - if (wasRecentlyDug(position)) return - - val isEven50Spread = (event.offset.x == 0.5f && event.offset.z == 0.5f) - - if (event.particleEffect.type == ParticleTypes.ENCHANT) { - if (event.count == 5 && event.speed == 0.05F && event.offset.y == 0.4F && isEven50Spread) { - markAsEnchanted(position) - } - return - } - - if (!wasRecentlyEnchanted(position)) return - - if (event.particleEffect.type == ParticleTypes.ENCHANTED_HIT - && event.count == 4 - && event.speed == 0.01F - && event.offset.y == 0.1f - && isEven50Spread - ) { - burrows[position] = BurrowType.START - } - if (event.particleEffect.type == ParticleTypes.CRIT - && event.count == 3 - && event.speed == 0.01F - && event.offset.y == 0.1F - && isEven50Spread - ) { - burrows[position] = BurrowType.MOB - } - if (event.particleEffect.type == ParticleTypes.DRIPPING_LAVA - && event.count == 2 - && event.speed == 0.01F - && event.offset.y == 0.1F - && event.offset.x == 0.35F && event.offset.z == 0.35f - ) { - burrows[position] = BurrowType.TREASURE - } - } - - @Subscribe - fun onRender(event: WorldRenderLastEvent) { - if (!DianaWaypoints.TConfig.nearbyWaypoints) return - renderInWorld(event) { - for ((location, burrow) in burrows) { - when (burrow) { - BurrowType.START -> color(.2f, .8f, .2f, 0.4f) - BurrowType.MOB -> color(0.3f, 0.4f, 0.9f, 0.4f) - BurrowType.TREASURE -> color(1f, 0.7f, 0.2f, 0.4f) - } - block(location) - } - } - } - - @Subscribe - fun onSwapWorld(worldReadyEvent: WorldReadyEvent) { - burrows.clear() - recentEnchantParticles.clear() - recentlyDugBurrows.clear() - lastBlockClick = null - } - - fun onBlockClick(blockPos: BlockPos) { - if (!DianaWaypoints.TConfig.nearbyWaypoints) return - burrows.remove(blockPos) - lastBlockClick = blockPos - } - - override val delegateFeature: FirmamentFeature - get() = DianaWaypoints -} - -fun Position.toBlockPos(): BlockPos { - return BlockPos(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z)) -} diff --git a/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt deleted file mode 100644 index 8926a95..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt +++ /dev/null @@ -1,224 +0,0 @@ - -package moe.nea.firmament.features.events.anniversity - -import io.github.notenoughupdates.moulconfig.observer.ObservableList -import io.github.notenoughupdates.moulconfig.xml.Bind -import moe.nea.jarvis.api.Point -import kotlin.time.Duration.Companion.seconds -import net.minecraft.entity.passive.PigEntity -import net.minecraft.util.math.BlockPos -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.EntityInteractionEvent -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.events.WorldReadyEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.gui.hud.MoulConfigHud -import moe.nea.firmament.rei.SBItemEntryDefinition -import moe.nea.firmament.repo.ItemNameLookup -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SHORT_NUMBER_FORMAT -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.TimeMark -import moe.nea.firmament.util.parseShortNumber -import moe.nea.firmament.util.useMatch - -object AnniversaryFeatures : FirmamentFeature { - override val identifier: String - get() = "anniversary" - - object TConfig : ManagedConfig(identifier) { - val enableShinyPigTracker by toggle("shiny-pigs") {true} - val trackPigCooldown by position("pig-hud", 200, 300) { Point(0.1, 0.2) } - } - - override val config: ManagedConfig? - get() = TConfig - - data class ClickedPig( - val clickedAt: TimeMark, - val startLocation: BlockPos, - val pigEntity: PigEntity - ) { - @Bind("timeLeft") - fun getTimeLeft(): Double = 1 - clickedAt.passedTime() / pigDuration - } - - val clickedPigs = ObservableList<ClickedPig>(mutableListOf()) - var lastClickedPig: PigEntity? = null - - val pigDuration = 90.seconds - - @Subscribe - fun onTick(event: TickEvent) { - clickedPigs.removeIf { it.clickedAt.passedTime() > pigDuration } - } - - val pattern = "SHINY! You extracted (?<reward>.*) from the piglet's orb!".toPattern() - - @Subscribe - fun onChat(event: ProcessChatEvent) { - if(!TConfig.enableShinyPigTracker)return - if (event.unformattedString == "Oink! Bring the pig back to the Shiny Orb!") { - val pig = lastClickedPig ?: return - // TODO: store proper location based on the orb location, maybe - val startLocation = pig.blockPos ?: return - clickedPigs.add(ClickedPig(TimeMark.now(), startLocation, pig)) - lastClickedPig = null - } - if (event.unformattedString == "SHINY! The orb is charged! Click on it for loot!") { - val player = MC.player ?: return - val lowest = - clickedPigs.minByOrNull { it.startLocation.getSquaredDistance(player.pos) } ?: return - clickedPigs.remove(lowest) - } - pattern.useMatch(event.unformattedString) { - val reward = group("reward") - val parsedReward = parseReward(reward) - addReward(parsedReward) - PigCooldown.rewards.atOnce { - PigCooldown.rewards.clear() - rewards.mapTo(PigCooldown.rewards) { PigCooldown.DisplayReward(it) } - } - } - } - - fun addReward(reward: Reward) { - val it = rewards.listIterator() - while (it.hasNext()) { - val merged = reward.mergeWith(it.next()) ?: continue - it.set(merged) - return - } - rewards.add(reward) - } - - val rewards = mutableListOf<Reward>() - - fun <T> ObservableList<T>.atOnce(block: () -> Unit) { - val oldObserver = observer - observer = null - block() - observer = oldObserver - update() - } - - sealed interface Reward { - fun mergeWith(other: Reward): Reward? - data class EXP(val amount: Double, val skill: String) : Reward { - override fun mergeWith(other: Reward): Reward? { - if (other is EXP && other.skill == skill) - return EXP(amount + other.amount, skill) - return null - } - } - - data class Coins(val amount: Double) : Reward { - override fun mergeWith(other: Reward): Reward? { - if (other is Coins) - return Coins(other.amount + amount) - return null - } - } - - data class Items(val amount: Int, val item: SkyblockId) : Reward { - override fun mergeWith(other: Reward): Reward? { - if (other is Items && other.item == item) - return Items(amount + other.amount, item) - return null - } - } - - data class Unknown(val text: String) : Reward { - override fun mergeWith(other: Reward): Reward? { - return null - } - } - } - - val expReward = "\\+(?<exp>$SHORT_NUMBER_FORMAT) (?<kind>[^ ]+) XP".toPattern() - val coinReward = "\\+(?<amount>$SHORT_NUMBER_FORMAT) coins".toPattern() - val itemReward = "(?:(?<amount>[0-9]+)x )?(?<name>.*)".toPattern() - fun parseReward(string: String): Reward { - expReward.useMatch<Unit>(string) { - val exp = parseShortNumber(group("exp")) - val kind = group("kind") - return Reward.EXP(exp, kind) - } - coinReward.useMatch<Unit>(string) { - val coins = parseShortNumber(group("amount")) - return Reward.Coins(coins) - } - itemReward.useMatch(string) { - val amount = group("amount")?.toIntOrNull() ?: 1 - val name = group("name") - val item = ItemNameLookup.guessItemByName(name, false) ?: return@useMatch - return Reward.Items(amount, item) - } - return Reward.Unknown(string) - } - - @Subscribe - fun onWorldClear(event: WorldReadyEvent) { - lastClickedPig = null - clickedPigs.clear() - } - - @Subscribe - fun onEntityClick(event: EntityInteractionEvent) { - if (event.entity is PigEntity) { - lastClickedPig = event.entity - } - } - - @Subscribe - fun init(event: WorldReadyEvent) { - PigCooldown.forceInit() - } - - object PigCooldown : MoulConfigHud("anniversary_pig", TConfig.trackPigCooldown) { - override fun shouldRender(): Boolean { - return clickedPigs.isNotEmpty() && TConfig.enableShinyPigTracker - } - - @Bind("pigs") - fun getPigs() = clickedPigs - - class DisplayReward(val backedBy: Reward) { - @Bind - fun count(): String { - return when (backedBy) { - is Reward.Coins -> backedBy.amount - is Reward.EXP -> backedBy.amount - is Reward.Items -> backedBy.amount - is Reward.Unknown -> 0 - }.toString() - } - - val itemStack = if (backedBy is Reward.Items) { - SBItemEntryDefinition.getEntry(backedBy.item, backedBy.amount) - } else { - SBItemEntryDefinition.getEntry(SkyblockId.NULL) - } - - @Bind - fun name(): String { - return when (backedBy) { - is Reward.Coins -> "Coins" - is Reward.EXP -> backedBy.skill - is Reward.Items -> itemStack.value.asItemStack().name.string - is Reward.Unknown -> backedBy.text - } - } - - @Bind - fun isKnown() = backedBy !is Reward.Unknown - } - - @get:Bind("rewards") - val rewards = ObservableList<DisplayReward>(mutableListOf()) - - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/events/carnival/CarnivalFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/events/carnival/CarnivalFeatures.kt deleted file mode 100644 index 1e6d97a..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/events/carnival/CarnivalFeatures.kt +++ /dev/null @@ -1,17 +0,0 @@ - -package moe.nea.firmament.features.events.carnival - -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig - -object CarnivalFeatures : FirmamentFeature { - object TConfig : ManagedConfig(identifier) { - val enableBombSolver by toggle("bombs-solver") { true } - val displayTutorials by toggle("tutorials") { true } - } - - override val config: ManagedConfig? - get() = TConfig - override val identifier: String - get() = "carnival" -} diff --git a/src/main/kotlin/moe/nea/firmament/features/events/carnival/MinesweeperHelper.kt b/src/main/kotlin/moe/nea/firmament/features/events/carnival/MinesweeperHelper.kt deleted file mode 100644 index 06caf86..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/events/carnival/MinesweeperHelper.kt +++ /dev/null @@ -1,276 +0,0 @@ - -package moe.nea.firmament.features.events.carnival - -import io.github.notenoughupdates.moulconfig.observer.ObservableList -import io.github.notenoughupdates.moulconfig.platform.ModernItemStack -import io.github.notenoughupdates.moulconfig.xml.Bind -import java.util.UUID -import net.minecraft.block.Blocks -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import net.minecraft.text.ClickEvent -import net.minecraft.text.Text -import net.minecraft.util.math.BlockPos -import net.minecraft.world.WorldAccess -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.commands.thenExecute -import moe.nea.firmament.events.AttackBlockEvent -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.events.EntityUpdateEvent -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.WorldReadyEvent -import moe.nea.firmament.events.WorldRenderLastEvent -import moe.nea.firmament.features.debug.DebugLogger -import moe.nea.firmament.util.LegacyFormattingCode -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.MoulConfigUtils -import moe.nea.firmament.util.ScreenUtil -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.item.createSkullItem -import moe.nea.firmament.util.render.RenderInWorldContext -import moe.nea.firmament.util.setSkyBlockFirmamentUiId -import moe.nea.firmament.util.skyBlockId -import moe.nea.firmament.util.useMatch - -object MinesweeperHelper { - val sandBoxLow = BlockPos(-112, 72, -11) - val sandBoxHigh = BlockPos(-106, 72, -5) - val boardSize = Pair(sandBoxHigh.x - sandBoxLow.x, sandBoxHigh.z - sandBoxLow.z) - - val gameStartMessage = "[NPC] Carnival Pirateman: Good luck, matey!" - val gameEndMessage = "Fruit Digging" - val bombPattern = "MINES! There (are|is) (?<bombCount>[0-8]) bombs? hidden nearby\\.".toPattern() - val startGameQuestion = "[NPC] Carnival Pirateman: Would ye like to do some Fruit Digging?" - - - enum class Piece( - @get:Bind("fruitName") - val fruitName: String, - val points: Int, - val specialAbility: String, - val totalPerBoard: Int, - val textureHash: String, - val fruitColor: LegacyFormattingCode, - ) { - COCONUT("Coconut", - 200, - "Prevents a bomb from exploding next turn", - 3, - "10ceb1455b471d016a9f06d25f6e468df9fcf223e2c1e4795b16e84fcca264ee", - LegacyFormattingCode.DARK_PURPLE), - APPLE("Apple", - 100, - "Gains 100 points for each apple dug up", - 8, - "17ea278d6225c447c5943d652798d0bbbd1418434ce8c54c54fdac79994ddd6c", - LegacyFormattingCode.GREEN), - WATERMELON("Watermelon", - 100, - "Blows up an adjacent fruit for half the points", - 4, - "efe4ef83baf105e8dee6cf03dfe7407f1911b3b9952c891ae34139560f2931d6", - LegacyFormattingCode.DARK_BLUE), - DURIAN("Durian", - 800, - "Halves the points earned in the next turn", - 2, - "ac268d36c2c6047ffeec00124096376b56dbb4d756a55329363a1b27fcd659cd", - LegacyFormattingCode.DARK_PURPLE), - MANGO("Mango", - 300, - "Just an ordinary fruit", - 10, - "f363a62126a35537f8189343a22660de75e810c6ac004a7d3da65f1c040a839", - LegacyFormattingCode.GREEN), - DRAGON_FRUIT("Dragonfruit", - 1200, - "Halves the points earned in the next turn", - 1, - "3cc761bcb0579763d9b8ab6b7b96fa77eb6d9605a804d838fec39e7b25f95591", - LegacyFormattingCode.LIGHT_PURPLE), - POMEGRANATE("Pomegranate", - 200, - "Grants an extra 50% more points in the next turn", - 4, - "40824d18079042d5769f264f44394b95b9b99ce689688cc10c9eec3f882ccc08", - LegacyFormattingCode.DARK_BLUE), - CHERRY("Cherry", - 200, - "The second cherry grants 300 bonus points", - 2, - "c92b099a62cd2fbf8ada09dec145c75d7fda4dc57b968bea3a8fa11e37aa48b2", - LegacyFormattingCode.DARK_PURPLE), - BOMB("Bomb", - -1, - "Destroys nearby fruit", - 15, - "a76a2811d1e176a07b6d0a657b910f134896ce30850f6e80c7c83732d85381ea", - LegacyFormattingCode.DARK_RED), - RUM("Rum", - -1, - "Stops your dowsing ability for one turn", - 5, - "407b275d28b927b1bf7f6dd9f45fbdad2af8571c54c8f027d1bff6956fbf3c16", - LegacyFormattingCode.YELLOW), - ; - - val textureUrl = "http://textures.minecraft.net/texture/$textureHash" - val itemStack = createSkullItem(UUID.randomUUID(), textureUrl) - .setSkyBlockFirmamentUiId("MINESWEEPER_$name") - - @Bind - fun getIcon() = ModernItemStack.of(itemStack) - - @Bind - fun pieceLabel() = fruitColor.formattingCode + fruitName - - @Bind - fun boardLabel() = "§a$totalPerBoard§7/§rboard" - - @Bind("description") - fun getDescription() = buildString { - append(specialAbility) - if (points >= 0) { - append(" Default points: $points.") - } - } - } - - object TutorialScreen { - @get:Bind("pieces") - val pieces = ObservableList(Piece.entries.toList().reversed()) - - @get:Bind("modes") - val modes = ObservableList(DowsingMode.entries.toList()) - } - - enum class DowsingMode( - val itemType: Item, - @get:Bind("feature") - val feature: String, - @get:Bind("description") - val description: String, - ) { - MINES(Items.IRON_SHOVEL, "Bomb detection", "Tells you how many bombs are near the block"), - ANCHOR(Items.DIAMOND_SHOVEL, "Lowest fruit", "Shows you which block nearby contains the lowest scoring fruit"), - TREASURE(Items.GOLDEN_SHOVEL, "Highest fruit", "Tells you which kind of fruit is the highest scoring nearby"), - ; - - @Bind("itemType") - fun getItemStack() = ModernItemStack.of(ItemStack(itemType)) - - companion object { - val id = SkyblockId("CARNIVAL_SHOVEL") - fun fromItem(itemStack: ItemStack): DowsingMode? { - if (itemStack.skyBlockId != id) return null - return DowsingMode.entries.find { it.itemType == itemStack.item } - } - } - } - - data class BoardPosition( - val x: Int, - val y: Int - ) { - fun toBlockPos() = BlockPos(sandBoxLow.x + x, sandBoxLow.y, sandBoxLow.z + y) - - fun getBlock(world: WorldAccess) = world.getBlockState(toBlockPos()).block - fun isUnopened(world: WorldAccess) = getBlock(world) == Blocks.SAND - fun isOpened(world: WorldAccess) = getBlock(world) == Blocks.SANDSTONE - fun isScorched(world: WorldAccess) = getBlock(world) == Blocks.SANDSTONE_STAIRS - - companion object { - fun fromBlockPos(blockPos: BlockPos): BoardPosition? { - if (blockPos.y != sandBoxLow.y) return null - val x = blockPos.x - sandBoxLow.x - val y = blockPos.z - sandBoxLow.z - if (x < 0 || x >= boardSize.first) return null - if (y < 0 || y >= boardSize.second) return null - return BoardPosition(x, y) - } - } - } - - data class GameState( - val nearbyBombs: MutableMap<BoardPosition, Int> = mutableMapOf(), - val knownBombPositions: MutableSet<BoardPosition> = mutableSetOf(), - var lastClickedPosition: BoardPosition? = null, - var lastDowsingMode: DowsingMode? = null, - ) - - var gameState: GameState? = null - val log = DebugLogger("minesweeper") - - @Subscribe - fun onCommand(event: CommandEvent.SubCommand) { - event.subcommand("minesweepertutorial") { - thenExecute { - ScreenUtil.setScreenLater(MoulConfigUtils.loadScreen("carnival/minesweeper_tutorial", - TutorialScreen, - null)) - } - } - } - - @Subscribe - fun onWorldChange(event: WorldReadyEvent) { - gameState = null - } - - @Subscribe - fun onChat(event: ProcessChatEvent) { - if (CarnivalFeatures.TConfig.displayTutorials && event.unformattedString == startGameQuestion) { - MC.sendChat(Text.translatable("firmament.carnival.tutorial.minesweeper").styled { - it.withClickEvent(ClickEvent(ClickEvent.Action.RUN_COMMAND, "/firm minesweepertutorial")) - }) - } - if (!CarnivalFeatures.TConfig.enableBombSolver) { - gameState = null // TODO: replace this which a watchable property - return - } - if (event.unformattedString == gameStartMessage) { - gameState = GameState() - log.log { "Game started" } - } - if (event.unformattedString.trim() == gameEndMessage) { - gameState = null // TODO: add a loot tracker maybe? probably not, i dont think people care - log.log { "Finished game" } - } - val gs = gameState ?: return - bombPattern.useMatch(event.unformattedString) { - val bombCount = group("bombCount").toInt() - log.log { "Marking ${gs.lastClickedPosition} as having $bombCount nearby" } - val pos = gs.lastClickedPosition ?: return - gs.nearbyBombs[pos] = bombCount - } - } - - @Subscribe - fun onMobChange(event: EntityUpdateEvent) { - val gs = gameState ?: return - if (event !is EntityUpdateEvent.TrackedDataUpdate) return - // TODO: listen to state - } - - @Subscribe - fun onBlockClick(event: AttackBlockEvent) { - val gs = gameState ?: return - val boardPosition = BoardPosition.fromBlockPos(event.blockPos) - log.log { "Breaking block at ${event.blockPos} ($boardPosition)" } - gs.lastClickedPosition = boardPosition - gs.lastDowsingMode = DowsingMode.fromItem(event.player.inventory.mainHandStack) - } - - @Subscribe - fun onRender(event: WorldRenderLastEvent) { - val gs = gameState ?: return - RenderInWorldContext.renderInWorld(event) { - for ((pos, bombCount) in gs.nearbyBombs) { - this.text(pos.toBlockPos().up().toCenterPos(), Text.literal("§a$bombCount \uD83D\uDCA3")) - } - } - } - - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/fixes/CompatibliltyFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/fixes/CompatibliltyFeatures.kt deleted file mode 100644 index 7c43cf6..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/fixes/CompatibliltyFeatures.kt +++ /dev/null @@ -1,51 +0,0 @@ - - -package moe.nea.firmament.features.fixes - -import net.fabricmc.loader.api.FabricLoader -import net.superkat.explosiveenhancement.api.ExplosiveApi -import net.minecraft.particle.ParticleTypes -import net.minecraft.util.math.Vec3d -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ParticleSpawnEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.MC - -object CompatibliltyFeatures : FirmamentFeature { - override val identifier: String - get() = "compatibility" - - object TConfig : ManagedConfig(identifier) { - val enhancedExplosions by toggle("explosion-enabled") { false } - val explosionSize by integer("explosion-power", 10, 50) { 1 } - } - - override val config: ManagedConfig? - get() = TConfig - - interface ExplosiveApiWrapper { - fun spawnParticle(vec3d: Vec3d, power: Float) - } - - class ExplosiveApiWrapperImpl : ExplosiveApiWrapper { - override fun spawnParticle(vec3d: Vec3d, power: Float) { - ExplosiveApi.spawnParticles(MC.world, vec3d.x, vec3d.y, vec3d.z, TConfig.explosionSize / 10F) - } - } - - val explosiveApiWrapper = if (FabricLoader.getInstance().isModLoaded("explosiveenhancement")) { - ExplosiveApiWrapperImpl() - } else null - - @Subscribe - fun onExplosion(it: ParticleSpawnEvent) { - if (TConfig.enhancedExplosions && - it.particleEffect.type == ParticleTypes.EXPLOSION_EMITTER && - explosiveApiWrapper != null - ) { - it.cancel() - explosiveApiWrapper.spawnParticle(it.position, 2F) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/fixes/Fixes.kt b/src/main/kotlin/moe/nea/firmament/features/fixes/Fixes.kt deleted file mode 100644 index d7b7a1c..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/fixes/Fixes.kt +++ /dev/null @@ -1,71 +0,0 @@ - - -package moe.nea.firmament.features.fixes - -import moe.nea.jarvis.api.Point -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable -import net.minecraft.client.MinecraftClient -import net.minecraft.client.option.KeyBinding -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.text.Text -import net.minecraft.util.Arm -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.HudRenderEvent -import moe.nea.firmament.events.WorldKeyboardEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.errorBoundary - -object Fixes : FirmamentFeature { - override val identifier: String - get() = "fixes" - - object TConfig : ManagedConfig(identifier) { - val fixUnsignedPlayerSkins by toggle("player-skins") { true } - var autoSprint by toggle("auto-sprint") { false } - val autoSprintKeyBinding by keyBindingWithDefaultUnbound("auto-sprint-keybinding") - val autoSprintHud by position("auto-sprint-hud", 80, 10) { Point(0.0, 1.0) } - val peekChat by keyBindingWithDefaultUnbound("peek-chat") - } - - override val config: ManagedConfig - get() = TConfig - - fun handleIsPressed( - keyBinding: KeyBinding, - cir: CallbackInfoReturnable<Boolean> - ) { - if (keyBinding === MinecraftClient.getInstance().options.sprintKey && TConfig.autoSprint && MC.player?.isSprinting != true) - cir.returnValue = true - } - - @Subscribe - fun onRenderHud(it: HudRenderEvent) { - if (!TConfig.autoSprintKeyBinding.isBound) return - it.context.matrices.push() - TConfig.autoSprintHud.applyTransformations(it.context.matrices) - it.context.drawText( - MC.font, Text.translatable( - if (TConfig.autoSprint) - "firmament.fixes.auto-sprint.on" - else if (MC.player?.isSprinting == true) - "firmament.fixes.auto-sprint.sprinting" - else - "firmament.fixes.auto-sprint.not-sprinting" - ), 0, 0, -1, false - ) - it.context.matrices.pop() - } - - @Subscribe - fun onWorldKeyboard(it: WorldKeyboardEvent) { - if (it.matches(TConfig.autoSprintKeyBinding)) { - TConfig.autoSprint = !TConfig.autoSprint - } - } - - fun shouldPeekChat(): Boolean { - return TConfig.peekChat.isPressed(atLeast = true) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt deleted file mode 100644 index 031ef78..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/CraftingOverlay.kt +++ /dev/null @@ -1,66 +0,0 @@ - - -package moe.nea.firmament.features.inventory - -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen -import net.minecraft.item.ItemStack -import net.minecraft.util.Formatting -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.SlotRenderEvents -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry -import moe.nea.firmament.rei.SBItemEntryDefinition -import moe.nea.firmament.rei.recipes.SBCraftingRecipe -import moe.nea.firmament.util.MC - -object CraftingOverlay : FirmamentFeature { - - private var screen: GenericContainerScreen? = null - private var recipe: SBCraftingRecipe? = null - private val craftingOverlayIndices = listOf( - 10, 11, 12, - 19, 20, 21, - 28, 29, 30, - ) - - - fun setOverlay(screen: GenericContainerScreen, recipe: SBCraftingRecipe) { - this.screen = screen - this.recipe = recipe - } - - override val identifier: String - get() = "crafting-overlay" - - @Subscribe - fun onSlotRender(event: SlotRenderEvents.After) { - val slot = event.slot - val recipe = this.recipe ?: return - if (slot.inventory != screen?.screenHandler?.inventory) return - val recipeIndex = craftingOverlayIndices.indexOf(slot.index) - if (recipeIndex < 0) return - val expectedItem = recipe.neuRecipe.inputs[recipeIndex] - val actualStack = slot.stack ?: ItemStack.EMPTY!! - val actualEntry = SBItemEntryDefinition.getEntry(actualStack).value - if ((actualEntry.skyblockId.neuItem != expectedItem.itemId || actualEntry.getStackSize() < expectedItem.amount) && expectedItem.amount.toInt() != 0) { - event.context.fill( - event.slot.x, - event.slot.y, - event.slot.x + 16, - event.slot.y + 16, - 0x80FF0000.toInt() - ) - } - if (!slot.hasStack()) { - val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value - event.context.drawItem(itemStack, event.slot.x, event.slot.y) - event.context.drawItemInSlot( - MC.font, - itemStack, - event.slot.x, - event.slot.y, - "${Formatting.RED}${expectedItem.amount.toInt()}" - ) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/ItemRarityCosmetics.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/ItemRarityCosmetics.kt deleted file mode 100644 index 566a813..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/ItemRarityCosmetics.kt +++ /dev/null @@ -1,85 +0,0 @@ - - -package moe.nea.firmament.features.inventory - -import java.awt.Color -import net.minecraft.client.gui.DrawContext -import net.minecraft.item.ItemStack -import net.minecraft.util.Formatting -import net.minecraft.util.Identifier -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.HotbarItemRenderEvent -import moe.nea.firmament.events.SlotRenderEvents -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.item.loreAccordingToNbt -import moe.nea.firmament.util.lastNotNullOfOrNull -import moe.nea.firmament.util.memoize -import moe.nea.firmament.util.memoizeIdentity -import moe.nea.firmament.util.unformattedString - -object ItemRarityCosmetics : FirmamentFeature { - override val identifier: String - get() = "item-rarity-cosmetics" - - object TConfig : ManagedConfig(identifier) { - val showItemRarityBackground by toggle("background") { false } - val showItemRarityInHotbar by toggle("background-hotbar") { false } - } - - override val config: ManagedConfig - get() = TConfig - - private val rarityToColor = mapOf( - "UNCOMMON" to Formatting.GREEN, - "COMMON" to Formatting.WHITE, - "RARE" to Formatting.DARK_BLUE, - "EPIC" to Formatting.DARK_PURPLE, - "LEGENDARY" to Formatting.GOLD, - "LEGENJERRY" to Formatting.GOLD, - "MYTHIC" to Formatting.LIGHT_PURPLE, - "DIVINE" to Formatting.BLUE, - "SPECIAL" to Formatting.DARK_RED, - "SUPREME" to Formatting.DARK_RED, - ).mapValues { - val c = Color(it.value.colorValue!!) - Triple(c.red / 255F, c.green / 255F, c.blue / 255F) - } - - private fun getSkyblockRarity0(itemStack: ItemStack): Triple<Float, Float, Float>? { - return itemStack.loreAccordingToNbt.lastNotNullOfOrNull { - val entry = it.unformattedString - rarityToColor.entries.find { (k, v) -> k in entry }?.value - } - } - - val getSkyblockRarity = ::getSkyblockRarity0.memoizeIdentity(100) - - - fun drawItemStackRarity(drawContext: DrawContext, x: Int, y: Int, item: ItemStack) { - val (r, g, b) = getSkyblockRarity(item) ?: return - drawContext.drawSprite( - x, y, - 0, - 16, 16, - MC.guiAtlasManager.getSprite(Identifier.of("firmament:item_rarity_background")), - r, g, b, 1F - ) - } - - - @Subscribe - fun onRenderSlot(it: SlotRenderEvents.Before) { - if (!TConfig.showItemRarityBackground) return - val stack = it.slot.stack ?: return - drawItemStackRarity(it.context, it.slot.x, it.slot.y, stack) - } - - @Subscribe - fun onRenderHotbarItem(it: HotbarItemRenderEvent) { - if (!TConfig.showItemRarityInHotbar) return - val stack = it.item - drawItemStackRarity(it.context, it.x, it.y, stack) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt deleted file mode 100644 index c61f8e8..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/PriceData.kt +++ /dev/null @@ -1,51 +0,0 @@ - - -package moe.nea.firmament.features.inventory - -import net.minecraft.text.Text -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ItemTooltipEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.repo.HypixelStaticData -import moe.nea.firmament.util.FirmFormatters -import moe.nea.firmament.util.skyBlockId - -object PriceData : FirmamentFeature { - override val identifier: String - get() = "price-data" - - object TConfig : ManagedConfig(identifier) { - val tooltipEnabled by toggle("enable-always") { true } - val enableKeybinding by keyBindingWithDefaultUnbound("enable-keybind") - } - - override val config get() = TConfig - - @Subscribe - fun onItemTooltip(it: ItemTooltipEvent) { - if (!TConfig.tooltipEnabled && !TConfig.enableKeybinding.isPressed()) { - return - } - val sbId = it.stack.skyBlockId - val bazaarData = HypixelStaticData.bazaarData[sbId] - val lowestBin = HypixelStaticData.lowestBin[sbId] - if (bazaarData != null) { - it.lines.add(Text.literal("")) - it.lines.add( - Text.stringifiedTranslatable("firmament.tooltip.bazaar.sell-order", - FirmFormatters.formatCommas(bazaarData.quickStatus.sellPrice, 1)) - ) - it.lines.add( - Text.stringifiedTranslatable("firmament.tooltip.bazaar.buy-order", - FirmFormatters.formatCommas(bazaarData.quickStatus.buyPrice, 1)) - ) - } else if (lowestBin != null) { - it.lines.add(Text.literal("")) - it.lines.add( - Text.stringifiedTranslatable("firmament.tooltip.ah.lowestbin", - FirmFormatters.formatCommas(lowestBin, 1)) - ) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/SaveCursorPosition.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/SaveCursorPosition.kt deleted file mode 100644 index 1c55753..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/SaveCursorPosition.kt +++ /dev/null @@ -1,66 +0,0 @@ - - -package moe.nea.firmament.features.inventory - -import kotlin.math.absoluteValue -import kotlin.time.Duration.Companion.milliseconds -import net.minecraft.client.util.InputUtil -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.TimeMark -import moe.nea.firmament.util.assertNotNullOr - -object SaveCursorPosition : FirmamentFeature { - override val identifier: String - get() = "save-cursor-position" - - object TConfig : ManagedConfig(identifier) { - val enable by toggle("enable") { true } - val tolerance by duration("tolerance", 10.milliseconds, 5000.milliseconds) { 500.milliseconds } - } - - override val config: TConfig - get() = TConfig - - var savedPositionedP1: Pair<Double, Double>? = null - var savedPosition: SavedPosition? = null - - data class SavedPosition( - val middle: Pair<Double, Double>, - val cursor: Pair<Double, Double>, - val savedAt: TimeMark = TimeMark.now() - ) - - @JvmStatic - fun saveCursorOriginal(positionedX: Double, positionedY: Double) { - savedPositionedP1 = Pair(positionedX, positionedY) - } - - @JvmStatic - fun loadCursor(middleX: Double, middleY: Double): Pair<Double, Double>? { - if (!TConfig.enable) return null - val lastPosition = savedPosition?.takeIf { it.savedAt.passedTime() < TConfig.tolerance } - savedPosition = null - if (lastPosition != null && - (lastPosition.middle.first - middleX).absoluteValue < 1 && - (lastPosition.middle.second - middleY).absoluteValue < 1 - ) { - InputUtil.setCursorParameters( - MC.window.handle, - InputUtil.GLFW_CURSOR_NORMAL, - lastPosition.cursor.first, - lastPosition.cursor.second - ) - return lastPosition.cursor - } - return null - } - - @JvmStatic - fun saveCursorMiddle(middleX: Double, middleY: Double) { - if (!TConfig.enable) return - val cursorPos = assertNotNullOr(savedPositionedP1) { return } - savedPosition = SavedPosition(Pair(middleX, middleY), cursorPos) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt deleted file mode 100644 index a50d8fb..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/SlotLocking.kt +++ /dev/null @@ -1,203 +0,0 @@ - - -@file:UseSerializers(DashlessUUIDSerializer::class) - -package moe.nea.firmament.features.inventory - -import com.mojang.blaze3d.systems.RenderSystem -import java.util.UUID -import org.lwjgl.glfw.GLFW -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import kotlinx.serialization.serializer -import net.minecraft.client.gui.screen.ingame.HandledScreen -import net.minecraft.entity.player.PlayerInventory -import net.minecraft.screen.GenericContainerScreenHandler -import net.minecraft.screen.slot.SlotActionType -import net.minecraft.util.Identifier -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.HandledScreenKeyPressedEvent -import moe.nea.firmament.events.IsSlotProtectedEvent -import moe.nea.firmament.events.SlotRenderEvents -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.keybindings.SavedKeyBinding -import moe.nea.firmament.mixins.accessor.AccessorHandledScreen -import moe.nea.firmament.util.CommonSoundEffects -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SBData -import moe.nea.firmament.util.SkyBlockIsland -import moe.nea.firmament.util.data.ProfileSpecificDataHolder -import moe.nea.firmament.util.item.displayNameAccordingToNbt -import moe.nea.firmament.util.item.loreAccordingToNbt -import moe.nea.firmament.util.json.DashlessUUIDSerializer -import moe.nea.firmament.util.skyblockUUID -import moe.nea.firmament.util.unformattedString - -object SlotLocking : FirmamentFeature { - override val identifier: String - get() = "slot-locking" - - @Serializable - data class Data( - val lockedSlots: MutableSet<Int> = mutableSetOf(), - val lockedSlotsRift: MutableSet<Int> = mutableSetOf(), - - val lockedUUIDs: MutableSet<UUID> = mutableSetOf(), - ) - - object TConfig : ManagedConfig(identifier) { - val lockSlot by keyBinding("lock") { GLFW.GLFW_KEY_L } - val lockUUID by keyBindingWithOutDefaultModifiers("lock-uuid") { - SavedKeyBinding(GLFW.GLFW_KEY_L, shift = true) - } - } - - override val config: TConfig - get() = TConfig - - object DConfig : ProfileSpecificDataHolder<Data>(serializer(), "locked-slots", ::Data) - - val lockedUUIDs get() = DConfig.data?.lockedUUIDs - - val lockedSlots - get() = when (SBData.skyblockLocation) { - SkyBlockIsland.RIFT -> DConfig.data?.lockedSlotsRift - null -> null - else -> DConfig.data?.lockedSlots - } - - fun isSalvageScreen(screen: HandledScreen<*>?): Boolean { - if (screen == null) return false - return screen.title.unformattedString.contains("Salvage Item") - } - - fun isTradeScreen(screen: HandledScreen<*>?): Boolean { - if (screen == null) return false - val handler = screen.screenHandler as? GenericContainerScreenHandler ?: return false - if (handler.inventory.size() < 9) return false - val middlePane = handler.inventory.getStack(handler.inventory.size() - 5) - if (middlePane == null) return false - return middlePane.displayNameAccordingToNbt?.unformattedString == "⇦ Your stuff" - } - - fun isNpcShop(screen: HandledScreen<*>?): Boolean { - if (screen == null) return false - val handler = screen.screenHandler as? GenericContainerScreenHandler ?: return false - if (handler.inventory.size() < 9) return false - val sellItem = handler.inventory.getStack(handler.inventory.size() - 5) - if (sellItem == null) return false - if (sellItem.displayNameAccordingToNbt?.unformattedString == "Sell Item") return true - val lore = sellItem.loreAccordingToNbt - return (lore.lastOrNull() ?: return false).unformattedString == "Click to buyback!" - } - - @Subscribe - fun onSalvageProtect(event: IsSlotProtectedEvent) { - if (event.slot == null) return - if (!event.slot.hasStack()) return - if (event.slot.stack.displayNameAccordingToNbt?.unformattedString != "Salvage Items") return - val inv = event.slot.inventory - var anyBlocked = false - for (i in 0 until event.slot.index) { - val stack = inv.getStack(i) - if (IsSlotProtectedEvent.shouldBlockInteraction(null, SlotActionType.THROW, stack)) - anyBlocked = true - } - if (anyBlocked) { - event.protectSilent() - } - } - - @Subscribe - fun onProtectUuidItems(event: IsSlotProtectedEvent) { - val doesNotDeleteItem = event.actionType == SlotActionType.SWAP - || event.actionType == SlotActionType.PICKUP - || event.actionType == SlotActionType.QUICK_MOVE - || event.actionType == SlotActionType.QUICK_CRAFT - || event.actionType == SlotActionType.CLONE - || event.actionType == SlotActionType.PICKUP_ALL - val isSellOrTradeScreen = - isNpcShop(MC.handledScreen) || isTradeScreen(MC.handledScreen) || isSalvageScreen(MC.handledScreen) - if ((!isSellOrTradeScreen || event.slot?.inventory !is PlayerInventory) - && doesNotDeleteItem - ) return - val stack = event.itemStack ?: return - val uuid = stack.skyblockUUID ?: return - if (uuid in (lockedUUIDs ?: return)) { - event.protect() - } - } - - @Subscribe - fun onProtectSlot(it: IsSlotProtectedEvent) { - if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) { - it.protect() - } - } - - @Subscribe - fun onLockUUID(it: HandledScreenKeyPressedEvent) { - if (!it.matches(TConfig.lockUUID)) return - val inventory = MC.handledScreen ?: return - inventory as AccessorHandledScreen - - val slot = inventory.focusedSlot_Firmament ?: return - val stack = slot.stack ?: return - val uuid = stack.skyblockUUID ?: return - val lockedUUIDs = lockedUUIDs ?: return - if (uuid in lockedUUIDs) { - lockedUUIDs.remove(uuid) - } else { - lockedUUIDs.add(uuid) - } - DConfig.markDirty() - CommonSoundEffects.playSuccess() - it.cancel() - } - - @Subscribe - fun onLockSlot(it: HandledScreenKeyPressedEvent) { - if (!it.matches(TConfig.lockSlot)) return - val inventory = MC.handledScreen ?: return - inventory as AccessorHandledScreen - - val slot = inventory.focusedSlot_Firmament ?: return - val lockedSlots = lockedSlots ?: return - if (slot.inventory is PlayerInventory) { - if (slot.index in lockedSlots) { - lockedSlots.remove(slot.index) - } else { - lockedSlots.add(slot.index) - } - DConfig.markDirty() - CommonSoundEffects.playSuccess() - } - } - - @Subscribe - fun onRenderSlotOverlay(it: SlotRenderEvents.After) { - val isSlotLocked = it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf()) - val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf()) - if (isSlotLocked || isUUIDLocked) { - RenderSystem.disableDepthTest() - it.context.drawSprite( - it.slot.x, it.slot.y, 0, - 16, 16, - MC.guiAtlasManager.getSprite( - when { - isSlotLocked -> - (Identifier.of("firmament:slot_locked")) - - isUUIDLocked -> - (Identifier.of("firmament:uuid_locked")) - - else -> - error("unreachable") - } - ) - ) - RenderSystem.enableDepthTest() - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButton.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButton.kt deleted file mode 100644 index 539edf2..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButton.kt +++ /dev/null @@ -1,85 +0,0 @@ - - -package moe.nea.firmament.features.inventory.buttons - -import com.mojang.brigadier.StringReader -import me.shedaniel.math.Dimension -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import kotlinx.serialization.Serializable -import net.minecraft.client.gui.DrawContext -import net.minecraft.command.CommandRegistryAccess -import net.minecraft.command.argument.ItemStackArgumentType -import net.minecraft.item.ItemStack -import net.minecraft.resource.featuretoggle.FeatureFlags -import net.minecraft.util.Identifier -import moe.nea.firmament.repo.ItemCache.asItemStack -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.memoize - -@Serializable -data class InventoryButton( - var x: Int, - var y: Int, - var anchorRight: Boolean, - var anchorBottom: Boolean, - var icon: String? = "", - var command: String? = "", -) { - companion object { - val itemStackParser by lazy { - ItemStackArgumentType.itemStack(CommandRegistryAccess.of(MC.defaultRegistries, - FeatureFlags.VANILLA_FEATURES)) - } - val dimensions = Dimension(18, 18) - val getItemForName = ::getItemForName0.memoize(1024) - fun getItemForName0(icon: String): ItemStack { - val repoItem = RepoManager.getNEUItem(SkyblockId(icon)) - var itemStack = repoItem.asItemStack(idHint = SkyblockId(icon)) - if (repoItem == null) { - val giveSyntaxItem = if (icon.startsWith("/give") || icon.startsWith("give")) - icon.split(" ", limit = 3).getOrNull(2) ?: icon - else icon - val componentItem = - runCatching { - itemStackParser.parse(StringReader(giveSyntaxItem)).createStack(1, false) - }.getOrNull() - if (componentItem != null) - itemStack = componentItem - } - return itemStack - } - } - - fun render(context: DrawContext) { - context.drawSprite( - 0, - 0, - 0, - dimensions.width, - dimensions.height, - MC.guiAtlasManager.getSprite(Identifier.of("firmament:inventory_button_background")) - ) - context.drawItem(getItem(), 1, 1) - } - - fun isValid() = !icon.isNullOrBlank() && !command.isNullOrBlank() - - fun getPosition(guiRect: Rectangle): Point { - return Point( - (if (anchorRight) guiRect.maxX else guiRect.minX) + x, - (if (anchorBottom) guiRect.maxY else guiRect.minY) + y, - ) - } - - fun getBounds(guiRect: Rectangle): Rectangle { - return Rectangle(getPosition(guiRect), dimensions) - } - - fun getItem(): ItemStack { - return getItemForName(icon ?: "") - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonEditor.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonEditor.kt deleted file mode 100644 index c57563e..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonEditor.kt +++ /dev/null @@ -1,184 +0,0 @@ - - -package moe.nea.firmament.features.inventory.buttons - -import io.github.notenoughupdates.moulconfig.common.IItemStack -import io.github.notenoughupdates.moulconfig.platform.ModernItemStack -import io.github.notenoughupdates.moulconfig.xml.Bind -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import org.lwjgl.glfw.GLFW -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.widget.ButtonWidget -import net.minecraft.client.util.InputUtil -import net.minecraft.text.Text -import net.minecraft.util.math.MathHelper -import net.minecraft.util.math.Vec2f -import moe.nea.firmament.util.ClipboardUtils -import moe.nea.firmament.util.FragmentGuiScreen -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.MoulConfigUtils - -class InventoryButtonEditor( - val lastGuiRect: Rectangle, -) : FragmentGuiScreen() { - inner class Editor(val originalButton: InventoryButton) { - @field:Bind - var command: String = originalButton.command ?: "" - - @field:Bind - var icon: String = originalButton.icon ?: "" - - @Bind - fun getItemIcon(): IItemStack { - save() - return ModernItemStack.of(InventoryButton.getItemForName(icon)) - } - - @Bind - fun delete() { - buttons.removeIf { it === originalButton } - popup = null - } - - fun save() { - originalButton.icon = icon - originalButton.command = command - } - } - - var buttons: MutableList<InventoryButton> = - InventoryButtons.DConfig.data.buttons.map { it.copy() }.toMutableList() - - override fun close() { - InventoryButtons.DConfig.data.buttons = buttons - InventoryButtons.DConfig.markDirty() - super.close() - } - - override fun init() { - super.init() - addDrawableChild( - ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.load-preset")) { - val t = ClipboardUtils.getTextContents() - val newButtons = InventoryButtonTemplates.loadTemplate(t) - if (newButtons != null) - buttons = newButtons.toMutableList() - } - .position(lastGuiRect.minX + 10, lastGuiRect.minY + 35) - .width(lastGuiRect.width - 20) - .build() - ) - addDrawableChild( - ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.save-preset")) { - ClipboardUtils.setTextContent(InventoryButtonTemplates.saveTemplate(buttons)) - } - .position(lastGuiRect.minX + 10, lastGuiRect.minY + 60) - .width(lastGuiRect.width - 20) - .build() - ) - } - - override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - super.render(context, mouseX, mouseY, delta) - context.matrices.push() - context.matrices.translate(0f, 0f, -10f) - context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1) - context.setShaderColor(1f, 1f, 1f, 1f) - context.matrices.pop() - for (button in buttons) { - val buttonPosition = button.getBounds(lastGuiRect) - context.matrices.push() - context.matrices.translate(buttonPosition.minX.toFloat(), buttonPosition.minY.toFloat(), 0F) - button.render(context) - context.matrices.pop() - } - } - - override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { - if (super.keyPressed(keyCode, scanCode, modifiers)) return true - if (keyCode == GLFW.GLFW_KEY_ESCAPE) { - close() - return true - } - return false - } - - override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { - if (super.mouseReleased(mouseX, mouseY, button)) return true - val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) } - if (clickedButton != null && !justPerformedAClickAction) { - createPopup(MoulConfigUtils.loadGui("button_editor_fragment", Editor(clickedButton)), Point(mouseX, mouseY)) - return true - } - justPerformedAClickAction = false - lastDraggedButton = null - return false - } - - override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean { - if (super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) return true - - if (initialDragMousePosition.distanceSquared(Vec2f(mouseX.toFloat(), mouseY.toFloat())) >= 4 * 4) { - initialDragMousePosition = Vec2f(-10F, -10F) - lastDraggedButton?.let { dragging -> - justPerformedAClickAction = true - val (anchorRight, anchorBottom, offsetX, offsetY) = getCoordsForMouse(mouseX.toInt(), mouseY.toInt()) - ?: return true - dragging.x = offsetX - dragging.y = offsetY - dragging.anchorRight = anchorRight - dragging.anchorBottom = anchorBottom - } - } - return false - } - - var lastDraggedButton: InventoryButton? = null - var justPerformedAClickAction = false - var initialDragMousePosition = Vec2f(-10F, -10F) - - data class AnchoredCoords( - val anchorRight: Boolean, - val anchorBottom: Boolean, - val offsetX: Int, - val offsetY: Int, - ) - - fun getCoordsForMouse(mx: Int, my: Int): AnchoredCoords? { - if (lastGuiRect.contains(mx, my) || lastGuiRect.contains( - Point( - mx + InventoryButton.dimensions.width, - my + InventoryButton.dimensions.height, - ) - ) - ) return null - - val anchorRight = mx > lastGuiRect.maxX - val anchorBottom = my > lastGuiRect.maxY - var offsetX = mx - if (anchorRight) lastGuiRect.maxX else lastGuiRect.minX - var offsetY = my - if (anchorBottom) lastGuiRect.maxY else lastGuiRect.minY - if (InputUtil.isKeyPressed(MC.window.handle, InputUtil.GLFW_KEY_LEFT_SHIFT)) { - offsetX = MathHelper.floor(offsetX / 20F) * 20 - offsetY = MathHelper.floor(offsetY / 20F) * 20 - } - return AnchoredCoords(anchorRight, anchorBottom, offsetX, offsetY) - } - - override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { - if (super.mouseClicked(mouseX, mouseY, button)) return true - val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) } - if (clickedButton != null) { - lastDraggedButton = clickedButton - initialDragMousePosition = Vec2f(mouseX.toFloat(), mouseY.toFloat()) - return true - } - val mx = mouseX.toInt() - val my = mouseY.toInt() - val (anchorRight, anchorBottom, offsetX, offsetY) = getCoordsForMouse(mx, my) ?: return true - buttons.add(InventoryButton(offsetX, offsetY, anchorRight, anchorBottom, null, null)) - justPerformedAClickAction = true - return true - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonTemplates.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonTemplates.kt deleted file mode 100644 index 99b544b..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtonTemplates.kt +++ /dev/null @@ -1,35 +0,0 @@ - - -package moe.nea.firmament.features.inventory.buttons - -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.TemplateUtil - -object InventoryButtonTemplates { - - val legacyPrefix = "NEUBUTTONS/" - val modernPrefix = "MAYBEONEDAYIWILLHAVEMYOWNFORMAT" - - fun loadTemplate(t: String): List<InventoryButton>? { - val buttons = TemplateUtil.maybeDecodeTemplate<List<String>>(legacyPrefix, t) ?: return null - return buttons.mapNotNull { - try { - Firmament.json.decodeFromString<InventoryButton>(it).also { - if (it.icon?.startsWith("extra:") == true || it.command?.any { it.isLowerCase() } == true) { - MC.sendChat(Text.translatable("firmament.inventory-buttons.import-failed")) - } - } - } catch (e: Exception) { - null - } - } - } - - fun saveTemplate(buttons: List<InventoryButton>): String { - return TemplateUtil.encodeTemplate(legacyPrefix, buttons.map { Firmament.json.encodeToString(it) }) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt deleted file mode 100644 index fa90d21..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/buttons/InventoryButtons.kt +++ /dev/null @@ -1,88 +0,0 @@ - - -package moe.nea.firmament.features.inventory.buttons - -import me.shedaniel.math.Rectangle -import kotlinx.serialization.Serializable -import kotlinx.serialization.serializer -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.HandledScreenClickEvent -import moe.nea.firmament.events.HandledScreenForegroundEvent -import moe.nea.firmament.events.HandledScreenPushREIEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.ScreenUtil -import moe.nea.firmament.util.data.DataHolder -import moe.nea.firmament.util.getRectangle - -object InventoryButtons : FirmamentFeature { - override val identifier: String - get() = "inventory-buttons" - - object TConfig : ManagedConfig(identifier) { - val _openEditor by button("open-editor") { - openEditor() - } - } - - object DConfig : DataHolder<Data>(serializer(), identifier, ::Data) - - @Serializable - data class Data( - var buttons: MutableList<InventoryButton> = mutableListOf() - ) - - - override val config: ManagedConfig - get() = TConfig - - fun getValidButtons() = DConfig.data.buttons.asSequence().filter { it.isValid() } - - @Subscribe - fun onRectangles(it: HandledScreenPushREIEvent) { - val bounds = it.screen.getRectangle() - for (button in getValidButtons()) { - val buttonBounds = button.getBounds(bounds) - it.block(buttonBounds) - } - } - - @Subscribe - fun onClickScreen(it: HandledScreenClickEvent) { - val bounds = it.screen.getRectangle() - for (button in getValidButtons()) { - val buttonBounds = button.getBounds(bounds) - if (buttonBounds.contains(it.mouseX, it.mouseY)) { - MC.sendCommand(button.command!! /* non null invariant covered by getValidButtons */) - break - } - } - } - - @Subscribe - fun onRenderForeground(it: HandledScreenForegroundEvent) { - val bounds = it.screen.getRectangle() - for (button in getValidButtons()) { - val buttonBounds = button.getBounds(bounds) - it.context.matrices.push() - it.context.matrices.translate(buttonBounds.minX.toFloat(), buttonBounds.minY.toFloat(), 0F) - button.render(it.context) - it.context.matrices.pop() - } - lastRectangle = bounds - } - - var lastRectangle: Rectangle? = null - fun openEditor() { - ScreenUtil.setScreenLater( - InventoryButtonEditor( - lastRectangle ?: Rectangle( - MC.window.scaledWidth / 2 - 100, - MC.window.scaledHeight / 2 - 100, - 200, 200, - ) - ) - ) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageBackingHandle.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageBackingHandle.kt deleted file mode 100644 index 1015578..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageBackingHandle.kt +++ /dev/null @@ -1,53 +0,0 @@ - - -package moe.nea.firmament.features.inventory.storageoverlay - -import net.minecraft.client.gui.screen.Screen -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen -import net.minecraft.screen.GenericContainerScreenHandler -import moe.nea.firmament.util.ifMatches -import moe.nea.firmament.util.unformattedString - -/** - * A handle representing the state of the "server side" screens. - */ -sealed interface StorageBackingHandle { - - sealed interface HasBackingScreen { - val handler: GenericContainerScreenHandler - } - - /** - * The main storage overview is open. Clicking on a slot will open that page. This page is accessible via `/storage` - */ - data class Overview(override val handler: GenericContainerScreenHandler) : StorageBackingHandle, HasBackingScreen - - /** - * An individual storage page is open. This may be a backpack or an enderchest page. This page is accessible via - * the [Overview] or via `/ec <index + 1>` for enderchest pages. - */ - data class Page(override val handler: GenericContainerScreenHandler, val storagePageSlot: StoragePageSlot) : - StorageBackingHandle, HasBackingScreen - - companion object { - private val enderChestName = "^Ender Chest \\(([1-9])/[1-9]\\)$".toRegex() - private val backPackName = "^.+Backpack \\(Slot #([0-9]+)\\)$".toRegex() - - /** - * Parse a screen into a [StorageBackingHandle]. If this returns null it means that the screen is not - * representable as a [StorageBackingHandle], meaning another screen is open, for example the enderchest icon - * selection screen. - */ - fun fromScreen(screen: Screen?): StorageBackingHandle? { - if (screen == null) return null - if (screen !is GenericContainerScreen) return null - val title = screen.title.unformattedString - if (title == "Storage") return Overview(screen.screenHandler) - return title.ifMatches(enderChestName) { - Page(screen.screenHandler, StoragePageSlot.ofEnderChestPage(it.groupValues[1].toInt())) - } ?: title.ifMatches(backPackName) { - Page(screen.screenHandler, StoragePageSlot.ofBackPackPage(it.groupValues[1].toInt())) - } - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageData.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageData.kt deleted file mode 100644 index 7555c56..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageData.kt +++ /dev/null @@ -1,21 +0,0 @@ - - -@file:UseSerializers(SortedMapSerializer::class) -package moe.nea.firmament.features.inventory.storageoverlay - -import java.util.SortedMap -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import moe.nea.firmament.util.SortedMapSerializer - -@Serializable -data class StorageData( - val storageInventories: SortedMap<StoragePageSlot, StorageInventory> = sortedMapOf() -) { - @Serializable - data class StorageInventory( - var title: String, - val slot: StoragePageSlot, - var inventory: VirtualInventory?, - ) -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlay.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlay.kt deleted file mode 100644 index b615c73..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlay.kt +++ /dev/null @@ -1,154 +0,0 @@ - - -package moe.nea.firmament.features.inventory.storageoverlay - -import java.util.SortedMap -import kotlinx.serialization.serializer -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen -import net.minecraft.client.gui.screen.ingame.HandledScreen -import net.minecraft.entity.player.PlayerInventory -import net.minecraft.item.Items -import net.minecraft.network.packet.c2s.play.CloseHandledScreenC2SPacket -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ScreenChangeEvent -import moe.nea.firmament.events.SlotClickEvent -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.customgui.customGui -import moe.nea.firmament.util.data.ProfileSpecificDataHolder - -object StorageOverlay : FirmamentFeature { - - - object Data : ProfileSpecificDataHolder<StorageData>(serializer(), "storage-data", ::StorageData) - - override val identifier: String - get() = "storage-overlay" - - object TConfig : ManagedConfig(identifier) { - val alwaysReplace by toggle("always-replace") { true } - val columns by integer("rows", 1, 10) { 3 } - val scrollSpeed by integer("scroll-speed", 1, 50) { 10 } - val inverseScroll by toggle("inverse-scroll") { false } - val padding by integer("padding", 1, 20) { 5 } - val margin by integer("margin", 1, 60) { 20 } - } - - fun adjustScrollSpeed(amount: Double): Double { - return amount * TConfig.scrollSpeed * (if (TConfig.inverseScroll) 1 else -1) - } - - override val config: TConfig - get() = TConfig - - var lastStorageOverlay: StorageOverviewScreen? = null - var skipNextStorageOverlayBackflip = false - var currentHandler: StorageBackingHandle? = null - - @Subscribe - fun onTick(event: TickEvent) { - rememberContent(currentHandler ?: return) - } - - @Subscribe - fun onClick(event: SlotClickEvent) { - if (lastStorageOverlay != null && event.slot.inventory !is PlayerInventory && event.slot.index < 9 - && event.stack.item != Items.BLACK_STAINED_GLASS_PANE - ) { - skipNextStorageOverlayBackflip = true - } - } - - @Subscribe - fun onScreenChange(it: ScreenChangeEvent) { - if (it.old == null && it.new == null) return - val storageOverlayScreen = it.old as? StorageOverlayScreen - ?: ((it.old as? HandledScreen<*>)?.customGui as? StorageOverlayCustom)?.overview - var storageOverviewScreen = it.old as? StorageOverviewScreen - val screen = it.new as? GenericContainerScreen - val oldHandler = currentHandler - currentHandler = StorageBackingHandle.fromScreen(screen) - rememberContent(currentHandler) - if (storageOverviewScreen != null && oldHandler is StorageBackingHandle.HasBackingScreen) { - val player = MC.player - assert(player != null) - player?.networkHandler?.sendPacket(CloseHandledScreenC2SPacket(oldHandler.handler.syncId)) - if (player?.currentScreenHandler === oldHandler.handler) { - player.currentScreenHandler = player.playerScreenHandler - } - } - storageOverviewScreen = storageOverviewScreen ?: lastStorageOverlay - if (it.new == null && storageOverlayScreen != null && !storageOverlayScreen.isExiting) { - it.overrideScreen = storageOverlayScreen - return - } - if (storageOverviewScreen != null - && !storageOverviewScreen.isClosing - && (currentHandler is StorageBackingHandle.Overview || currentHandler == null) - ) { - if (skipNextStorageOverlayBackflip) { - skipNextStorageOverlayBackflip = false - } else { - it.overrideScreen = storageOverviewScreen - lastStorageOverlay = null - } - return - } - screen ?: return - screen.customGui = StorageOverlayCustom( - currentHandler ?: return, - screen, - storageOverlayScreen ?: (if (TConfig.alwaysReplace) StorageOverlayScreen() else return)) - } - - fun rememberContent(handler: StorageBackingHandle?) { - handler ?: return - // TODO: Make all of these functions work on deltas / updates instead of the entire contents - val data = Data.data?.storageInventories ?: return - when (handler) { - is StorageBackingHandle.Overview -> rememberStorageOverview(handler, data) - is StorageBackingHandle.Page -> rememberPage(handler, data) - } - Data.markDirty() - } - - private fun rememberStorageOverview( - handler: StorageBackingHandle.Overview, - data: SortedMap<StoragePageSlot, StorageData.StorageInventory> - ) { - for ((index, stack) in handler.handler.stacks.withIndex()) { - // Ignore unloaded item stacks - if (stack.isEmpty) continue - val slot = StoragePageSlot.fromOverviewSlotIndex(index) ?: continue - val isEmpty = stack.item in StorageOverviewScreen.emptyStorageSlotItems - if (slot in data) { - if (isEmpty) - data.remove(slot) - continue - } - if (!isEmpty) { - data[slot] = StorageData.StorageInventory(slot.defaultName(), slot, null) - } - } - } - - private fun rememberPage( - handler: StorageBackingHandle.Page, - data: SortedMap<StoragePageSlot, StorageData.StorageInventory> - ) { - // TODO: FIXME: FIXME NOW: Definitely don't copy all of this every tick into persistence - val newStacks = - VirtualInventory(handler.handler.stacks.take(handler.handler.rows * 9).drop(9).map { it.copy() }) - data.compute(handler.storagePageSlot) { slot, existingInventory -> - (existingInventory ?: StorageData.StorageInventory( - slot.defaultName(), - slot, - null - )).also { - it.inventory = newStacks - } - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlayCustom.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlayCustom.kt deleted file mode 100644 index d0d9114..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlayCustom.kt +++ /dev/null @@ -1,98 +0,0 @@ - -package moe.nea.firmament.features.inventory.storageoverlay - -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen -import net.minecraft.entity.player.PlayerInventory -import net.minecraft.screen.slot.Slot -import moe.nea.firmament.mixins.accessor.AccessorHandledScreen -import moe.nea.firmament.util.customgui.CustomGui - -class StorageOverlayCustom( - val handler: StorageBackingHandle, - val screen: GenericContainerScreen, - val overview: StorageOverlayScreen, -) : CustomGui() { - override fun onVoluntaryExit(): Boolean { - overview.isExiting = true - return super.onVoluntaryExit() - } - - override fun getBounds(): List<Rectangle> { - return overview.getBounds() - } - - override fun afterSlotRender(context: DrawContext, slot: Slot) { - if (slot.inventory !is PlayerInventory) - context.disableScissor() - } - - override fun beforeSlotRender(context: DrawContext, slot: Slot) { - if (slot.inventory !is PlayerInventory) - overview.createScissors(context) - } - - override fun onInit() { - overview.init(MinecraftClient.getInstance(), screen.width, screen.height) - overview.init() - screen as AccessorHandledScreen - screen.x_Firmament = overview.measurements.x - screen.y_Firmament = overview.measurements.y - screen.backgroundWidth_Firmament = overview.measurements.totalWidth - screen.backgroundHeight_Firmament = overview.measurements.totalHeight - } - - override fun isPointOverSlot(slot: Slot, xOffset: Int, yOffset: Int, pointX: Double, pointY: Double): Boolean { - if (!super.isPointOverSlot(slot, xOffset, yOffset, pointX, pointY)) - return false - if (slot.inventory !is PlayerInventory) { - if (!overview.getScrollPanelInner().contains(pointX, pointY)) - return false - } - return true - } - - override fun shouldDrawForeground(): Boolean { - return false - } - - override fun mouseClick(mouseX: Double, mouseY: Double, button: Int): Boolean { - return overview.mouseClicked(mouseX, mouseY, button, (handler as? StorageBackingHandle.Page)?.storagePageSlot) - } - - override fun render(drawContext: DrawContext, delta: Float, mouseX: Int, mouseY: Int) { - overview.drawBackgrounds(drawContext) - overview.drawPages(drawContext, - mouseX, - mouseY, - delta, - (handler as? StorageBackingHandle.Page)?.storagePageSlot, - screen.screenHandler.slots.take(screen.screenHandler.rows * 9).drop(9), - Point((screen as AccessorHandledScreen).x_Firmament, screen.y_Firmament)) - overview.drawScrollBar(drawContext) - } - - override fun moveSlot(slot: Slot) { - val index = slot.index - if (index in 0..<36) { - val (x, y) = overview.getPlayerInventorySlotPosition(index) - slot.x = x - (screen as AccessorHandledScreen).x_Firmament - slot.y = y - screen.y_Firmament - } else { - slot.x = -100000 - slot.y = -100000 - } - } - - override fun mouseScrolled( - mouseX: Double, - mouseY: Double, - horizontalAmount: Double, - verticalAmount: Double - ): Boolean { - return overview.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlayScreen.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlayScreen.kt deleted file mode 100644 index 13c6974..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverlayScreen.kt +++ /dev/null @@ -1,296 +0,0 @@ - -package moe.nea.firmament.features.inventory.storageoverlay - -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.screen.Screen -import net.minecraft.screen.slot.Slot -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.ScreenUtil -import moe.nea.firmament.util.assertTrueOr - -class StorageOverlayScreen : Screen(Text.literal("")) { - - companion object { - val PLAYER_WIDTH = 184 - val PLAYER_HEIGHT = 91 - val PLAYER_Y_INSET = 3 - val SLOT_SIZE = 18 - val PADDING = 10 - val PAGE_WIDTH = SLOT_SIZE * 9 - val HOTBAR_X = 12 - val HOTBAR_Y = 67 - val MAIN_INVENTORY_Y = 9 - val SCROLL_BAR_WIDTH = 8 - val SCROLL_BAR_HEIGHT = 16 - } - - var isExiting: Boolean = false - var scroll: Float = 0F - var pageWidthCount = StorageOverlay.TConfig.columns - - inner class Measurements { - val innerScrollPanelWidth = PAGE_WIDTH * pageWidthCount + (pageWidthCount - 1) * PADDING - val overviewWidth = innerScrollPanelWidth + 3 * PADDING + SCROLL_BAR_WIDTH - val x = width / 2 - overviewWidth / 2 - val overviewHeight = minOf(3 * 18 * 6, height - PLAYER_HEIGHT - minOf(80, height / 10)) - val innerScrollPanelHeight = overviewHeight - PADDING * 2 - val y = height / 2 - (overviewHeight + PLAYER_HEIGHT) / 2 - val playerX = width / 2 - PLAYER_WIDTH / 2 - val playerY = y + overviewHeight - PLAYER_Y_INSET - val totalWidth = overviewWidth - val totalHeight = overviewHeight - PLAYER_Y_INSET + PLAYER_HEIGHT - } - - var measurements = Measurements() - - var lastRenderedInnerHeight = 0 - public override fun init() { - super.init() - pageWidthCount = StorageOverlay.TConfig.columns - .coerceAtMost((width - PADDING) / (PAGE_WIDTH + PADDING)) - .coerceAtLeast(1) - measurements = Measurements() - } - - override fun mouseScrolled( - mouseX: Double, - mouseY: Double, - horizontalAmount: Double, - verticalAmount: Double - ): Boolean { - scroll = (scroll + StorageOverlay.adjustScrollSpeed(verticalAmount)).toFloat() - .coerceAtMost(getMaxScroll()) - .coerceAtLeast(0F) - return true - } - - fun getMaxScroll() = lastRenderedInnerHeight.toFloat() - getScrollPanelInner().height - - val playerInventorySprite = Identifier.of("firmament:storageoverlay/player_inventory") - val upperBackgroundSprite = Identifier.of("firmament:storageoverlay/upper_background") - val slotRowSprite = Identifier.of("firmament:storageoverlay/storage_row") - val scrollbarBackground = Identifier.of("firmament:storageoverlay/scroll_bar_background") - val scrollbarKnob = Identifier.of("firmament:storageoverlay/scroll_bar_knob") - - override fun close() { - isExiting = true - super.close() - } - - override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - super.render(context, mouseX, mouseY, delta) - drawBackgrounds(context) - drawPages(context, mouseX, mouseY, delta, null, null, Point()) - drawScrollBar(context) - drawPlayerInventory(context, mouseX, mouseY, delta) - } - - fun getScrollbarPercentage(): Float { - return scroll / getMaxScroll() - } - - fun drawScrollBar(context: DrawContext) { - val sbRect = getScrollBarRect() - context.drawGuiTexture( - scrollbarBackground, - sbRect.minX, sbRect.minY, - sbRect.width, sbRect.height, - ) - context.drawGuiTexture( - scrollbarKnob, - sbRect.minX, sbRect.minY + (getScrollbarPercentage() * (sbRect.height - SCROLL_BAR_HEIGHT)).toInt(), - SCROLL_BAR_WIDTH, SCROLL_BAR_HEIGHT - ) - } - - fun drawBackgrounds(context: DrawContext) { - context.drawGuiTexture(upperBackgroundSprite, - measurements.x, - measurements.y, - 0, - measurements.overviewWidth, - measurements.overviewHeight) - context.drawGuiTexture(playerInventorySprite, - measurements.playerX, - measurements.playerY, - 0, - PLAYER_WIDTH, - PLAYER_HEIGHT) - } - - fun getPlayerInventorySlotPosition(int: Int): Pair<Int, Int> { - if (int < 9) { - return Pair(measurements.playerX + int * SLOT_SIZE + HOTBAR_X, HOTBAR_Y + measurements.playerY) - } - return Pair( - measurements.playerX + (int % 9) * SLOT_SIZE + HOTBAR_X, - measurements.playerY + (int / 9 - 1) * SLOT_SIZE + MAIN_INVENTORY_Y - ) - } - - fun drawPlayerInventory(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - val items = MC.player?.inventory?.main ?: return - items.withIndex().forEach { (index, item) -> - val (x, y) = getPlayerInventorySlotPosition(index) - context.drawItem(item, x, y, 0) - context.drawItemInSlot(textRenderer, item, x, y) - } - } - - fun getScrollBarRect(): Rectangle { - return Rectangle(measurements.x + PADDING + measurements.innerScrollPanelWidth + PADDING, - measurements.y + PADDING, - SCROLL_BAR_WIDTH, - measurements.innerScrollPanelHeight) - } - - fun getScrollPanelInner(): Rectangle { - return Rectangle(measurements.x + PADDING, - measurements.y + PADDING, - measurements.innerScrollPanelWidth, - measurements.innerScrollPanelHeight) - } - - fun createScissors(context: DrawContext) { - val rect = getScrollPanelInner() - context.enableScissor( - rect.minX, rect.minY, - rect.maxX, rect.maxY - ) - } - - fun drawPages( - context: DrawContext, mouseX: Int, mouseY: Int, delta: Float, - excluding: StoragePageSlot?, - slots: List<Slot>?, - slotOffset: Point - ) { - createScissors(context) - val data = StorageOverlay.Data.data ?: StorageData() - layoutedForEach(data) { rect, page, inventory -> - drawPage(context, - rect.x, - rect.y, - page, inventory, - if (excluding == page) slots else null, - slotOffset - ) - } - context.disableScissor() - } - - override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { - return mouseClicked(mouseX, mouseY, button, null) - } - - fun mouseClicked(mouseX: Double, mouseY: Double, button: Int, activePage: StoragePageSlot?): Boolean { - if (getScrollPanelInner().contains(mouseX, mouseY)) { - val data = StorageOverlay.Data.data ?: StorageData() - layoutedForEach(data) { rect, page, _ -> - if (rect.contains(mouseX, mouseY) && activePage != page && button == 0) { - page.navigateTo() - return true - } - } - return false - } - val sbRect = getScrollBarRect() - if (sbRect.contains(mouseX, mouseY)) { - // TODO: support dragging of the mouse and such - val percentage = (mouseY - sbRect.getY()) / sbRect.getHeight() - scroll = (getMaxScroll() * percentage).toFloat() - mouseScrolled(0.0, 0.0, 0.0, 0.0) - return true - } - return false - } - - private inline fun layoutedForEach( - data: StorageData, - func: ( - rectangle: Rectangle, - page: StoragePageSlot, inventory: StorageData.StorageInventory, - ) -> Unit - ) { - var yOffset = -scroll.toInt() - var xOffset = 0 - var maxHeight = 0 - for ((page, inventory) in data.storageInventories.entries) { - val currentHeight = inventory.inventory?.let { it.rows * SLOT_SIZE + 4 + textRenderer.fontHeight } - ?: 18 - maxHeight = maxOf(maxHeight, currentHeight) - val rect = Rectangle( - measurements.x + PADDING + (PAGE_WIDTH + PADDING) * xOffset, - yOffset + measurements.y + PADDING, - PAGE_WIDTH, - currentHeight - ) - func(rect, page, inventory) - xOffset++ - if (xOffset >= pageWidthCount) { - yOffset += maxHeight - xOffset = 0 - maxHeight = 0 - } - } - lastRenderedInnerHeight = maxHeight + yOffset + scroll.toInt() - } - - fun drawPage( - context: DrawContext, - x: Int, - y: Int, - page: StoragePageSlot, - inventory: StorageData.StorageInventory, - slots: List<Slot>?, - slotOffset: Point, - ): Int { - val inv = inventory.inventory - if (inv == null) { - context.drawGuiTexture(upperBackgroundSprite, x, y, PAGE_WIDTH, 18) - context.drawText(textRenderer, - Text.literal("TODO: open this page"), - x + 4, - y + 4, - -1, - true) - return 18 - } - assertTrueOr(slots == null || slots.size == inv.stacks.size) { return 0 } - val name = page.defaultName() - context.drawText(textRenderer, Text.literal(name), x + 4, y + 2, - if (slots == null) 0xFFFFFFFF.toInt() else 0xFFFFFF00.toInt(), true) - context.drawGuiTexture(slotRowSprite, x, y + 4 + textRenderer.fontHeight, PAGE_WIDTH, inv.rows * SLOT_SIZE) - inv.stacks.forEachIndexed { index, stack -> - val slotX = (index % 9) * SLOT_SIZE + x + 1 - val slotY = (index / 9) * SLOT_SIZE + y + 4 + textRenderer.fontHeight + 1 - if (slots == null) { - context.drawItem(stack, slotX, slotY) - context.drawItemInSlot(textRenderer, stack, slotX, slotY) - } else { - val slot = slots[index] - slot.x = slotX - slotOffset.x - slot.y = slotY - slotOffset.y - } - } - return inv.rows * SLOT_SIZE + 4 + textRenderer.fontHeight - } - - fun getBounds(): List<Rectangle> { - return listOf( - Rectangle(measurements.x, - measurements.y, - measurements.overviewWidth, - measurements.overviewHeight), - Rectangle(measurements.playerX, - measurements.playerY, - PLAYER_WIDTH, - PLAYER_HEIGHT)) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverviewScreen.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverviewScreen.kt deleted file mode 100644 index 2cbd54e..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StorageOverviewScreen.kt +++ /dev/null @@ -1,123 +0,0 @@ - - -package moe.nea.firmament.features.inventory.storageoverlay - -import org.lwjgl.glfw.GLFW -import kotlin.math.max -import net.minecraft.block.Blocks -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.screen.Screen -import net.minecraft.item.Item -import net.minecraft.item.Items -import net.minecraft.text.Text -import net.minecraft.util.DyeColor -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.toShedaniel - -class StorageOverviewScreen() : Screen(Text.empty()) { - companion object { - val emptyStorageSlotItems = listOf<Item>( - Blocks.RED_STAINED_GLASS_PANE.asItem(), - Blocks.BROWN_STAINED_GLASS_PANE.asItem(), - Items.GRAY_DYE - ) - val pageWidth get() = 19 * 9 - } - - val content = StorageOverlay.Data.data ?: StorageData() - var isClosing = false - - var scroll = 0 - var lastRenderedHeight = 0 - - override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - super.render(context, mouseX, mouseY, delta) - context.fill(0, 0, width, height, 0x90000000.toInt()) - layoutedForEach { (key, value), offsetX, offsetY -> - context.matrices.push() - context.matrices.translate(offsetX.toFloat(), offsetY.toFloat(), 0F) - renderStoragePage(context, value, mouseX - offsetX, mouseY - offsetY) - context.matrices.pop() - } - } - - inline fun layoutedForEach(onEach: (data: Pair<StoragePageSlot, StorageData.StorageInventory>, offsetX: Int, offsetY: Int) -> Unit) { - var offsetY = 0 - var currentMaxHeight = StorageOverlay.config.margin - StorageOverlay.config.padding - scroll - var totalHeight = -currentMaxHeight - content.storageInventories.onEachIndexed { index, (key, value) -> - val pageX = (index % StorageOverlay.config.columns) - if (pageX == 0) { - currentMaxHeight += StorageOverlay.config.padding - offsetY += currentMaxHeight - totalHeight += currentMaxHeight - currentMaxHeight = 0 - } - val xPosition = - width / 2 - (StorageOverlay.config.columns * (pageWidth + StorageOverlay.config.padding) - StorageOverlay.config.padding) / 2 + pageX * (pageWidth + StorageOverlay.config.padding) - onEach(Pair(key, value), xPosition, offsetY) - val height = getStorePageHeight(value) - currentMaxHeight = max(currentMaxHeight, height) - } - lastRenderedHeight = totalHeight + currentMaxHeight - } - - override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { - layoutedForEach { (k, p), x, y -> - val rx = mouseX - x - val ry = mouseY - y - if (rx in (0.0..pageWidth.toDouble()) && ry in (0.0..getStorePageHeight(p).toDouble())) { - close() - StorageOverlay.lastStorageOverlay = this - k.navigateTo() - return true - } - } - return super.mouseClicked(mouseX, mouseY, button) - } - - fun getStorePageHeight(page: StorageData.StorageInventory): Int { - return page.inventory?.rows?.let { it * 19 + MC.font.fontHeight + 2 } ?: 60 - } - - override fun mouseScrolled( - mouseX: Double, - mouseY: Double, - horizontalAmount: Double, - verticalAmount: Double - ): Boolean { - scroll = - (scroll + StorageOverlay.adjustScrollSpeed(verticalAmount)).toInt() - .coerceAtMost(lastRenderedHeight - height + 2 * StorageOverlay.config.margin).coerceAtLeast(0) - return true - } - - private fun renderStoragePage(context: DrawContext, page: StorageData.StorageInventory, mouseX: Int, mouseY: Int) { - context.drawText(MC.font, page.title, 2, 2, -1, true) - val inventory = page.inventory - if (inventory == null) { - // TODO: Missing texture - context.fill(0, 0, pageWidth, 60, DyeColor.RED.toShedaniel().darker(4.0).color) - context.drawCenteredTextWithShadow(MC.font, Text.literal("Not loaded yet"), pageWidth / 2, 30, -1) - return - } - - for ((index, stack) in inventory.stacks.withIndex()) { - val x = (index % 9) * 19 - val y = (index / 9) * 19 + MC.font.fontHeight + 2 - if (((mouseX - x) in 0 until 18) && ((mouseY - y) in 0 until 18)) { - context.fill(x, y, x + 18, y + 18, 0x80808080.toInt()) - } else { - context.fill(x, y, x + 18, y + 18, 0x40808080.toInt()) - } - context.drawItem(stack, x + 1, y + 1) - context.drawItemInSlot(MC.font, stack, x + 1, y + 1) - } - } - - override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { - if (keyCode == GLFW.GLFW_KEY_ESCAPE) - isClosing = true - return super.keyPressed(keyCode, scanCode, modifiers) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StoragePageSlot.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StoragePageSlot.kt deleted file mode 100644 index 9259415..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/StoragePageSlot.kt +++ /dev/null @@ -1,66 +0,0 @@ - - -package moe.nea.firmament.features.inventory.storageoverlay - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import moe.nea.firmament.util.MC - -@Serializable(with = StoragePageSlot.Serializer::class) -data class StoragePageSlot(val index: Int) : Comparable<StoragePageSlot> { - object Serializer : KSerializer<StoragePageSlot> { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("StoragePageSlot", PrimitiveKind.INT) - - override fun deserialize(decoder: Decoder): StoragePageSlot { - return StoragePageSlot(decoder.decodeInt()) - } - - override fun serialize(encoder: Encoder, value: StoragePageSlot) { - encoder.encodeInt(value.index) - } - } - - init { - assert(index in 0 until (3 * 9)) - } - - val isEnderChest get() = index < 9 - val isBackPack get() = !isEnderChest - val slotIndexInOverviewPage get() = if (isEnderChest) index + 9 else index + 18 - fun defaultName(): String = if (isEnderChest) "Ender Chest #${index + 1}" else "Backpack #${index - 9 + 1}" - - fun navigateTo() { - if (isBackPack) { - MC.sendCommand("backpack ${index - 9 + 1}") - } else { - MC.sendCommand("enderchest ${index + 1}") - } - } - - companion object { - fun fromOverviewSlotIndex(slot: Int): StoragePageSlot? { - if (slot in 9 until 18) return StoragePageSlot(slot - 9) - if (slot in 27 until 45) return StoragePageSlot(slot - 27 + 9) - return null - } - - fun ofEnderChestPage(slot: Int): StoragePageSlot { - assert(slot in 1..9) - return StoragePageSlot(slot - 1) - } - - fun ofBackPackPage(slot: Int): StoragePageSlot { - assert(slot in 1..18) - return StoragePageSlot(slot - 1 + 9) - } - } - - override fun compareTo(other: StoragePageSlot): Int { - return this.index - other.index - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/VirtualInventory.kt b/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/VirtualInventory.kt deleted file mode 100644 index e07df8a..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/inventory/storageoverlay/VirtualInventory.kt +++ /dev/null @@ -1,65 +0,0 @@ - - -package moe.nea.firmament.features.inventory.storageoverlay - -import io.ktor.util.decodeBase64Bytes -import io.ktor.util.encodeBase64 -import java.io.ByteArrayInputStream -import java.io.ByteArrayOutputStream -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NbtCompound -import net.minecraft.nbt.NbtIo -import net.minecraft.nbt.NbtList -import net.minecraft.nbt.NbtOps -import net.minecraft.nbt.NbtSizeTracker - -@Serializable(with = VirtualInventory.Serializer::class) -data class VirtualInventory( - val stacks: List<ItemStack> -) { - val rows = stacks.size / 9 - - init { - assert(stacks.size % 9 == 0) - assert(stacks.size / 9 in 1..5) - } - - - object Serializer : KSerializer<VirtualInventory> { - const val INVENTORY = "INVENTORY" - override val descriptor: SerialDescriptor - get() = PrimitiveSerialDescriptor("VirtualInventory", PrimitiveKind.STRING) - - override fun deserialize(decoder: Decoder): VirtualInventory { - val s = decoder.decodeString() - val n = NbtIo.readCompressed(ByteArrayInputStream(s.decodeBase64Bytes()), NbtSizeTracker.of(100_000_000)) - val items = n.getList(INVENTORY, NbtCompound.COMPOUND_TYPE.toInt()) - return VirtualInventory(items.map { - it as NbtCompound - if (it.isEmpty) ItemStack.EMPTY - else runCatching { - ItemStack.CODEC.parse(NbtOps.INSTANCE, it).orThrow - }.getOrElse { ItemStack.EMPTY } - }) - } - - override fun serialize(encoder: Encoder, value: VirtualInventory) { - val list = NbtList() - value.stacks.forEach { - if (it.isEmpty) list.add(NbtCompound()) - else list.add(runCatching { ItemStack.CODEC.encode(it, NbtOps.INSTANCE, NbtCompound()).orThrow } - .getOrElse { NbtCompound() }) - } - val baos = ByteArrayOutputStream() - NbtIo.writeCompressed(NbtCompound().also { it.put(INVENTORY, list) }, baos) - encoder.encodeString(baos.toByteArray().encodeBase64()) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/mining/Histogram.kt b/src/main/kotlin/moe/nea/firmament/features/mining/Histogram.kt deleted file mode 100644 index ed48437..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/mining/Histogram.kt +++ /dev/null @@ -1,81 +0,0 @@ - -package moe.nea.firmament.features.mining - -import java.util.* -import kotlin.time.Duration -import moe.nea.firmament.util.TimeMark - -class Histogram<T>( - val maxSize: Int, - val maxDuration: Duration, -) { - - data class OrderedTimestamp(val timestamp: TimeMark, val order: Int) : Comparable<OrderedTimestamp> { - override fun compareTo(other: OrderedTimestamp): Int { - val o = timestamp.compareTo(other.timestamp) - if (o != 0) return o - return order.compareTo(other.order) - } - } - - val size: Int get() = dataPoints.size - private val dataPoints: NavigableMap<OrderedTimestamp, T> = TreeMap() - - private var order = Int.MIN_VALUE - - fun record(entry: T, timestamp: TimeMark = TimeMark.now()) { - dataPoints[OrderedTimestamp(timestamp, order++)] = entry - trim() - } - - fun oldestUpdate(): TimeMark { - trim() - return if (dataPoints.isEmpty()) TimeMark.now() else dataPoints.firstKey().timestamp - } - - fun latestUpdate(): TimeMark { - trim() - return if (dataPoints.isEmpty()) TimeMark.farPast() else dataPoints.lastKey().timestamp - } - - fun averagePer(valueExtractor: (T) -> Double, perDuration: Duration): Double? { - return aggregate( - seed = 0.0, - operator = { accumulator, entry, _ -> accumulator + valueExtractor(entry) }, - finish = { sum, beginning, end -> - val timespan = end - beginning - if (timespan > perDuration) - sum / (timespan / perDuration) - else null - }) - } - - fun <V, R> aggregate( - seed: V, - operator: (V, T, TimeMark) -> V, - finish: (V, TimeMark, TimeMark) -> R - ): R? { - trim() - var accumulator = seed - var min: TimeMark? = null - var max: TimeMark? = null - dataPoints.forEach { (key, value) -> - max = key.timestamp - if (min == null) - min = key.timestamp - accumulator = operator(accumulator, value, key.timestamp) - } - if (min == null) - return null - return finish(accumulator, min!!, max!!) - } - - private fun trim() { - while (maxSize < dataPoints.size) { - dataPoints.pollFirstEntry() - } - dataPoints.headMap(OrderedTimestamp(TimeMark.ago(maxDuration), Int.MAX_VALUE)).clear() - } - - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt b/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt deleted file mode 100644 index 7879f2d..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/mining/PickaxeAbility.kt +++ /dev/null @@ -1,176 +0,0 @@ - -package moe.nea.firmament.features.mining - -import java.util.regex.Pattern -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import net.minecraft.item.ItemStack -import net.minecraft.util.DyeColor -import net.minecraft.util.Hand -import net.minecraft.util.Identifier -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.HudRenderEvent -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.SlotClickEvent -import moe.nea.firmament.events.WorldReadyEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.DurabilityBarEvent -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SHORT_NUMBER_FORMAT -import moe.nea.firmament.util.TIME_PATTERN -import moe.nea.firmament.util.TimeMark -import moe.nea.firmament.util.extraAttributes -import moe.nea.firmament.util.item.displayNameAccordingToNbt -import moe.nea.firmament.util.item.loreAccordingToNbt -import moe.nea.firmament.util.parseShortNumber -import moe.nea.firmament.util.parseTimePattern -import moe.nea.firmament.util.render.RenderCircleProgress -import moe.nea.firmament.util.render.lerp -import moe.nea.firmament.util.toShedaniel -import moe.nea.firmament.util.unformattedString -import moe.nea.firmament.util.useMatch - -object PickaxeAbility : FirmamentFeature { - override val identifier: String - get() = "pickaxe-info" - - - object TConfig : ManagedConfig(identifier) { - val cooldownEnabled by toggle("ability-cooldown") { true } - val cooldownScale by integer("ability-scale", 16, 64) { 16 } - val drillFuelBar by toggle("fuel-bar") { true } - } - - var lobbyJoinTime = TimeMark.farPast() - var lastUsage = mutableMapOf<String, TimeMark>() - var abilityOverride: String? = null - var defaultAbilityDurations = mutableMapOf<String, Duration>( - "Mining Speed Boost" to 120.seconds, - "Pickobulus" to 110.seconds, - "Gemstone Infusion" to 140.seconds, - "Hazardous Miner" to 140.seconds, - "Maniac Miner" to 59.seconds, - "Vein Seeker" to 60.seconds - ) - - override val config: ManagedConfig - get() = TConfig - - fun getCooldownPercentage(name: String, cooldown: Duration): Double { - val sinceLastUsage = lastUsage[name]?.passedTime() ?: Duration.INFINITE - if (sinceLastUsage < cooldown) - return sinceLastUsage / cooldown - val sinceLobbyJoin = lobbyJoinTime.passedTime() - val halfCooldown = cooldown / 2 - if (sinceLobbyJoin < halfCooldown) { - return (sinceLobbyJoin / halfCooldown) - } - return 1.0 - } - - @Subscribe - fun onSlotClick(it: SlotClickEvent) { - if (MC.screen?.title?.unformattedString == "Heart of the Mountain") { - val name = it.stack.displayNameAccordingToNbt?.unformattedString ?: return - val cooldown = it.stack.loreAccordingToNbt.firstNotNullOfOrNull { - cooldownPattern.useMatch(it.unformattedString) { - parseTimePattern(group("cooldown")) - } - } ?: return - defaultAbilityDurations[name] = cooldown - } - } - - @Subscribe - fun onDurabilityBar(it: DurabilityBarEvent) { - if (!TConfig.drillFuelBar) return - val lore = it.item.loreAccordingToNbt - if (lore.lastOrNull()?.unformattedString?.contains("DRILL") != true) return - val maxFuel = lore.firstNotNullOfOrNull { - fuelPattern.useMatch(it.unformattedString) { - parseShortNumber(group("maxFuel")) - } - } ?: return - val extra = it.item.extraAttributes - if (!extra.contains("drill_fuel")) return - val fuel = extra.getInt("drill_fuel") - val percentage = fuel / maxFuel.toFloat() - it.barOverride = DurabilityBarEvent.DurabilityBar( - lerp( - DyeColor.RED.toShedaniel(), - DyeColor.GREEN.toShedaniel(), - percentage - ), percentage - ) - } - - @Subscribe - fun onChatMessage(it: ProcessChatEvent) { - abilityUsePattern.useMatch(it.unformattedString) { - lastUsage[group("name")] = TimeMark.now() - } - abilitySwitchPattern.useMatch(it.unformattedString) { - abilityOverride = group("ability") - } - } - - @Subscribe - fun onWorldReady(event: WorldReadyEvent) { - lastUsage.clear() - lobbyJoinTime = TimeMark.now() - abilityOverride = null - } - - val abilityUsePattern = Pattern.compile("You used your (?<name>.*) Pickaxe Ability!") - val fuelPattern = Pattern.compile("Fuel: .*/(?<maxFuel>$SHORT_NUMBER_FORMAT)") - - data class PickaxeAbilityData( - val name: String, - val cooldown: Duration, - ) - - fun getCooldownFromLore(itemStack: ItemStack): PickaxeAbilityData? { - val lore = itemStack.loreAccordingToNbt - if (!lore.any { it.unformattedString.contains("Breaking Power") == true }) - return null - val cooldown = lore.firstNotNullOfOrNull { - cooldownPattern.useMatch(it.unformattedString) { - 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 abilityPattern = Pattern.compile("Ability: (?<name>.*) {2}RIGHT CLICK") - val abilitySwitchPattern = - Pattern.compile("You selected (?<ability>.*) as your Pickaxe Ability\\. This ability will apply to all of your pickaxes!") - - - @Subscribe - fun renderHud(event: HudRenderEvent) { - if (!TConfig.cooldownEnabled) return - var ability = getCooldownFromLore(MC.player?.getStackInHand(Hand.MAIN_HAND) ?: return) ?: return - defaultAbilityDurations[ability.name] = ability.cooldown - val ao = abilityOverride - if (ao != ability.name && ao != null) { - ability = PickaxeAbilityData(ao, defaultAbilityDurations[ao] ?: 120.seconds) - } - event.context.matrices.push() - event.context.matrices.translate(MC.window.scaledWidth / 2F, MC.window.scaledHeight / 2F, 0F) - event.context.matrices.scale(TConfig.cooldownScale.toFloat(), TConfig.cooldownScale.toFloat(), 1F) - RenderCircleProgress.renderCircle( - event.context, Identifier.of("firmament", "textures/gui/circle.png"), - getCooldownPercentage(ability.name, ability.cooldown).toFloat(), - 0f, 1f, 0f, 1f - ) - event.context.matrices.pop() - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/mining/PristineProfitTracker.kt b/src/main/kotlin/moe/nea/firmament/features/mining/PristineProfitTracker.kt deleted file mode 100644 index f1bc7e5..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/mining/PristineProfitTracker.kt +++ /dev/null @@ -1,133 +0,0 @@ - -package moe.nea.firmament.features.mining - -import io.github.notenoughupdates.moulconfig.xml.Bind -import moe.nea.jarvis.api.Point -import kotlinx.serialization.Serializable -import kotlinx.serialization.serializer -import kotlin.time.Duration.Companion.seconds -import net.minecraft.text.Text -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.gui.hud.MoulConfigHud -import moe.nea.firmament.util.BazaarPriceStrategy -import moe.nea.firmament.util.FirmFormatters.formatCommas -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.data.ProfileSpecificDataHolder -import moe.nea.firmament.util.formattedString -import moe.nea.firmament.util.parseIntWithComma -import moe.nea.firmament.util.useMatch - -object PristineProfitTracker : FirmamentFeature { - override val identifier: String - get() = "pristine-profit" - - enum class GemstoneKind( - val label: String, - val flawedId: SkyblockId, - ) { - SAPPHIRE("Sapphire", SkyblockId("FLAWED_SAPPHIRE_GEM")), - RUBY("Ruby", SkyblockId("FLAWED_RUBY_GEM")), - AMETHYST("Amethyst", SkyblockId("FLAWED_AMETHYST_GEM")), - AMBER("Amber", SkyblockId("FLAWED_AMBER_GEM")), - TOPAZ("Topaz", SkyblockId("FLAWED_TOPAZ_GEM")), - JADE("Jade", SkyblockId("FLAWED_JADE_GEM")), - JASPER("Jasper", SkyblockId("FLAWED_JASPER_GEM")), - OPAL("Opal", SkyblockId("FLAWED_OPAL_GEM")), - } - - @Serializable - data class Data( - var maxMoneyPerSecond: Double = 1.0, - var maxCollectionPerSecond: Double = 1.0, - ) - - object DConfig : ProfileSpecificDataHolder<Data>(serializer(), identifier, ::Data) - - override val config: ManagedConfig? - get() = TConfig - - object TConfig : ManagedConfig(identifier) { - val timeout by duration("timeout", 0.seconds, 120.seconds) { 30.seconds } - val gui by position("position", 80, 30) { Point(0.05, 0.2) } - } - - val sellingStrategy = BazaarPriceStrategy.SELL_ORDER - - val pristineRegex = - "PRISTINE! You found . Flawed (?<kind>${ - GemstoneKind.entries.joinToString("|") { it.label } - }) Gemstone x(?<count>[0-9,]+)!".toPattern() - - val collectionHistogram = Histogram<Double>(10000, 180.seconds) - val moneyHistogram = Histogram<Double>(10000, 180.seconds) - - object ProfitHud : MoulConfigHud("pristine_profit", TConfig.gui) { - @field:Bind - var moneyCurrent: Double = 0.0 - - @field:Bind - var moneyMax: Double = 1.0 - - @field:Bind - var moneyText = "" - - @field:Bind - var collectionCurrent = 0.0 - - @field:Bind - var collectionMax = 1.0 - - @field:Bind - var collectionText = "" - override fun shouldRender(): Boolean = collectionHistogram.latestUpdate().passedTime() < TConfig.timeout - } - - val SECONDS_PER_HOUR = 3600 - val ROUGHS_PER_FLAWED = 80 - - fun updateUi() { - val collectionPerSecond = collectionHistogram.averagePer({ it }, 1.seconds) - val moneyPerSecond = moneyHistogram.averagePer({ it }, 1.seconds) - if (collectionPerSecond == null || moneyPerSecond == null) return - ProfitHud.collectionCurrent = collectionPerSecond - ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection", - formatCommas(collectionPerSecond * SECONDS_PER_HOUR, - 1)).formattedString() - ProfitHud.moneyCurrent = moneyPerSecond - ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money", - formatCommas(moneyPerSecond * SECONDS_PER_HOUR, 1)) - .formattedString() - val data = DConfig.data - if (data != null) { - if (data.maxCollectionPerSecond < collectionPerSecond && collectionHistogram.oldestUpdate() - .passedTime() > 30.seconds - ) { - data.maxCollectionPerSecond = collectionPerSecond - DConfig.markDirty() - } - if (data.maxMoneyPerSecond < moneyPerSecond && moneyHistogram.oldestUpdate().passedTime() > 30.seconds) { - data.maxMoneyPerSecond = moneyPerSecond - DConfig.markDirty() - } - ProfitHud.collectionMax = maxOf(data.maxCollectionPerSecond, collectionPerSecond) - ProfitHud.moneyMax = maxOf(data.maxMoneyPerSecond, moneyPerSecond) - } - } - - - @Subscribe - fun onMessage(it: ProcessChatEvent) { - pristineRegex.useMatch(it.unformattedString) { - val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase()) - val flawedCount = parseIntWithComma(group("count")) - val moneyAmount = sellingStrategy.getSellPrice(gemstoneKind.flawedId) * flawedCount - moneyHistogram.record(moneyAmount) - val collectionAmount = flawedCount * ROUGHS_PER_FLAWED - collectionHistogram.record(collectionAmount.toDouble()) - updateUi() - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/notifications/Notifications.kt b/src/main/kotlin/moe/nea/firmament/features/notifications/Notifications.kt deleted file mode 100644 index 8d912d1..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/notifications/Notifications.kt +++ /dev/null @@ -1,7 +0,0 @@ - -package moe.nea.firmament.features.notifications - -import moe.nea.firmament.features.FirmamentFeature - -object Notifications { -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/AlwaysPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/AlwaysPredicate.kt deleted file mode 100644 index 4dd28df..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/AlwaysPredicate.kt +++ /dev/null @@ -1,17 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import net.minecraft.item.ItemStack - -object AlwaysPredicate : FirmamentModelPredicate { - override fun test(stack: ItemStack): Boolean { - return true - } - - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): FirmamentModelPredicate { - return AlwaysPredicate - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt deleted file mode 100644 index 55a4f32..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt +++ /dev/null @@ -1,26 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import net.minecraft.item.ItemStack - -class AndPredicate(val children: Array<FirmamentModelPredicate>) : FirmamentModelPredicate { - override fun test(stack: ItemStack): Boolean { - return children.all { it.test(stack) } - } - - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): FirmamentModelPredicate { - val children = - (jsonElement as JsonArray) - .flatMap { - CustomModelOverrideParser.parsePredicates(it as JsonObject) - } - .toTypedArray() - return AndPredicate(children) - } - - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedModelExtra.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedModelExtra.kt deleted file mode 100644 index ae1f6d5..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedModelExtra.kt +++ /dev/null @@ -1,9 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import net.minecraft.client.render.model.BakedModel - -interface BakedModelExtra { - fun getHeadModel_firmament(): BakedModel? - fun setHeadModel_firmament(headModel: BakedModel?) -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt deleted file mode 100644 index c012883..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt +++ /dev/null @@ -1,8 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -interface BakedOverrideData { - fun getFirmamentOverrides(): Array<FirmamentModelPredicate>? - fun setFirmamentOverrides(overrides: Array<FirmamentModelPredicate>?) - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt deleted file mode 100644 index 18da54c..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt +++ /dev/null @@ -1,296 +0,0 @@ -@file:UseSerializers(BlockPosSerializer::class, IdentifierSerializer::class) - -package moe.nea.firmament.features.texturepack - -import java.util.concurrent.CompletableFuture -import net.fabricmc.loader.api.FabricLoader -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient -import kotlinx.serialization.UseSerializers -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.serializer -import kotlin.jvm.optionals.getOrNull -import net.minecraft.block.Block -import net.minecraft.block.BlockState -import net.minecraft.client.render.model.BakedModel -import net.minecraft.client.util.ModelIdentifier -import net.minecraft.registry.RegistryKey -import net.minecraft.registry.RegistryKeys -import net.minecraft.resource.ResourceManager -import net.minecraft.resource.SinglePreparationResourceReloader -import net.minecraft.util.Identifier -import net.minecraft.util.math.BlockPos -import net.minecraft.util.profiler.Profiler -import moe.nea.firmament.Firmament -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.compat.SodiumChunkReloader -import moe.nea.firmament.events.BakeExtraModelsEvent -import moe.nea.firmament.events.EarlyResourceReloadEvent -import moe.nea.firmament.events.FinalizeResourceManagerEvent -import moe.nea.firmament.events.SkyblockServerUpdateEvent -import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger -import moe.nea.firmament.util.IdentifierSerializer -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SBData -import moe.nea.firmament.util.SkyBlockIsland -import moe.nea.firmament.util.json.BlockPosSerializer -import moe.nea.firmament.util.json.SingletonSerializableList - - -object CustomBlockTextures { - @Serializable - data class CustomBlockOverride( - val modes: @Serializable(SingletonSerializableList::class) List<String>, - val area: List<Area>? = null, - val replacements: Map<Identifier, Replacement>, - ) - - @Serializable(with = Replacement.Serializer::class) - data class Replacement( - val block: Identifier, - val sound: Identifier?, - ) { - - @Transient - val blockModelIdentifier get() = ModelIdentifier(block.withPrefixedPath("block/"), "firmament") - - @Transient - val bakedModel: BakedModel by lazy(LazyThreadSafetyMode.NONE) { - MC.instance.bakedModelManager.getModel(blockModelIdentifier) - } - - @OptIn(ExperimentalSerializationApi::class) - @kotlinx.serialization.Serializer(Replacement::class) - object DefaultSerializer : KSerializer<Replacement> - - object Serializer : KSerializer<Replacement> { - val delegate = serializer<JsonElement>() - override val descriptor: SerialDescriptor - get() = delegate.descriptor - - override fun deserialize(decoder: Decoder): Replacement { - val jsonElement = decoder.decodeSerializableValue(delegate) - if (jsonElement is JsonPrimitive) { - require(jsonElement.isString) - return Replacement(Identifier.tryParse(jsonElement.content)!!, null) - } - return (decoder as JsonDecoder).json.decodeFromJsonElement(DefaultSerializer, jsonElement) - } - - override fun serialize(encoder: Encoder, value: Replacement) { - encoder.encodeSerializableValue(DefaultSerializer, value) - } - } - } - - @Serializable - data class Area( - val min: BlockPos, - val max: BlockPos, - ) { - @Transient - val realMin = BlockPos( - minOf(min.x, max.x), - minOf(min.y, max.y), - minOf(min.z, max.z), - ) - - @Transient - val realMax = BlockPos( - maxOf(min.x, max.x), - maxOf(min.y, max.y), - maxOf(min.z, max.z), - ) - - fun roughJoin(other: Area): Area { - return Area( - BlockPos( - minOf(realMin.x, other.realMin.x), - minOf(realMin.y, other.realMin.y), - minOf(realMin.z, other.realMin.z), - ), - BlockPos( - maxOf(realMax.x, other.realMax.x), - maxOf(realMax.y, other.realMax.y), - maxOf(realMax.z, other.realMax.z), - ) - ) - } - - fun contains(blockPos: BlockPos): Boolean { - return (blockPos.x in realMin.x..realMax.x) && - (blockPos.y in realMin.y..realMax.y) && - (blockPos.z in realMin.z..realMax.z) - } - } - - data class LocationReplacements( - val lookup: Map<Block, List<BlockReplacement>> - ) - - data class BlockReplacement( - val checks: List<Area>?, - val replacement: Replacement, - ) { - val roughCheck by lazy(LazyThreadSafetyMode.NONE) { - if (checks == null || checks.size < 3) return@lazy null - checks.reduce { acc, next -> acc.roughJoin(next) } - } - } - - data class BakedReplacements(val data: Map<SkyBlockIsland, LocationReplacements>) - - var allLocationReplacements: BakedReplacements = BakedReplacements(mapOf()) - var currentIslandReplacements: LocationReplacements? = null - - fun refreshReplacements() { - val location = SBData.skyblockLocation - val replacements = - if (CustomSkyBlockTextures.TConfig.enableBlockOverrides) location?.let(allLocationReplacements.data::get) - else null - val lastReplacements = currentIslandReplacements - currentIslandReplacements = replacements - if (lastReplacements != replacements) { - MC.nextTick { - MC.worldRenderer.chunks?.chunks?.forEach { - // false schedules rebuilds outside a 27 block radius to happen async - it.scheduleRebuild(false) - } - sodiumReloadTask?.run() - } - } - } - - private val sodiumReloadTask = runCatching { - SodiumChunkReloader() - }.getOrElse { - if (FabricLoader.getInstance().isModLoaded("sodium")) - logger.error("Could not create sodium chunk reloader") - null - } - - - fun matchesPosition(replacement: BlockReplacement, blockPos: BlockPos?): Boolean { - if (blockPos == null) return true - val rc = replacement.roughCheck - if (rc != null && !rc.contains(blockPos)) return false - val areas = replacement.checks - if (areas != null && !areas.any { it.contains(blockPos) }) return false - return true - } - - @JvmStatic - fun getReplacementModel(block: BlockState, blockPos: BlockPos?): BakedModel? { - return getReplacement(block, blockPos)?.bakedModel - } - - @JvmStatic - fun getReplacement(block: BlockState, blockPos: BlockPos?): Replacement? { - if (isInFallback() && blockPos == null) return null - val replacements = currentIslandReplacements?.lookup?.get(block.block) ?: return null - for (replacement in replacements) { - if (replacement.checks == null || matchesPosition(replacement, blockPos)) - return replacement.replacement - } - return null - } - - - @Subscribe - fun onLocation(event: SkyblockServerUpdateEvent) { - refreshReplacements() - } - - @Volatile - var preparationFuture: CompletableFuture<BakedReplacements> = CompletableFuture.completedFuture(BakedReplacements( - mapOf())) - - val insideFallbackCall = ThreadLocal.withInitial { 0 } - - @JvmStatic - fun enterFallbackCall() { - insideFallbackCall.set(insideFallbackCall.get() + 1) - } - - fun isInFallback() = insideFallbackCall.get() > 0 - - @JvmStatic - fun exitFallbackCall() { - insideFallbackCall.set(insideFallbackCall.get() - 1) - } - - @Subscribe - fun onEarlyReload(event: EarlyResourceReloadEvent) { - preparationFuture = CompletableFuture - .supplyAsync( - { prepare(event.resourceManager) }, event.preparationExecutor) - } - - @Subscribe - fun bakeExtraModels(event: BakeExtraModelsEvent) { - preparationFuture.join().data.values - .flatMap { it.lookup.values } - .flatten() - .mapTo(mutableSetOf()) { it.replacement.blockModelIdentifier } - .forEach { event.addNonItemModel(it) } - } - - private fun prepare(manager: ResourceManager): BakedReplacements { - val resources = manager.findResources("overrides/blocks") { - it.namespace == "firmskyblock" && it.path.endsWith(".json") - } - val map = mutableMapOf<SkyBlockIsland, MutableMap<Block, MutableList<BlockReplacement>>>() - for ((file, resource) in resources) { - val json = - Firmament.tryDecodeJsonFromStream<CustomBlockOverride>(resource.inputStream) - .getOrElse { ex -> - logger.error("Failed to load block texture override at $file", ex) - continue - } - for (mode in json.modes) { - val island = SkyBlockIsland.forMode(mode) - val islandMpa = map.getOrPut(island, ::mutableMapOf) - for ((blockId, replacement) in json.replacements) { - val block = MC.defaultRegistries.getWrapperOrThrow(RegistryKeys.BLOCK) - .getOptional(RegistryKey.of(RegistryKeys.BLOCK, blockId)) - .getOrNull() - if (block == null) { - logger.error("Failed to load block texture override at ${file}: unknown block '$blockId'") - continue - } - val replacements = islandMpa.getOrPut(block.value(), ::mutableListOf) - replacements.add(BlockReplacement(json.area, replacement)) - } - } - } - - return BakedReplacements(map.mapValues { LocationReplacements(it.value) }) - } - - @JvmStatic - fun patchIndigo(orig: BakedModel, pos: BlockPos, state: BlockState): BakedModel { - return getReplacementModel(state, pos) ?: orig - } - - @Subscribe - fun onStart(event: FinalizeResourceManagerEvent) { - event.resourceManager.registerReloader(object : - SinglePreparationResourceReloader<BakedReplacements>() { - override fun prepare(manager: ResourceManager, profiler: Profiler): BakedReplacements { - return preparationFuture.join() - } - - override fun apply(prepared: BakedReplacements, manager: ResourceManager, profiler: Profiler?) { - allLocationReplacements = prepared - refreshReplacements() - } - }) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalArmorOverrides.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalArmorOverrides.kt deleted file mode 100644 index 23577ee..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalArmorOverrides.kt +++ /dev/null @@ -1,106 +0,0 @@ - -@file:UseSerializers(IdentifierSerializer::class) - -package moe.nea.firmament.features.texturepack - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient -import kotlinx.serialization.UseSerializers -import net.minecraft.item.ArmorMaterial -import net.minecraft.item.ItemStack -import net.minecraft.resource.ResourceManager -import net.minecraft.resource.SinglePreparationResourceReloader -import net.minecraft.util.Identifier -import net.minecraft.util.profiler.Profiler -import moe.nea.firmament.Firmament -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.FinalizeResourceManagerEvent -import moe.nea.firmament.events.subscription.SubscriptionOwner -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger -import moe.nea.firmament.util.IdentifierSerializer -import moe.nea.firmament.util.IdentityCharacteristics -import moe.nea.firmament.util.computeNullableFunction -import moe.nea.firmament.util.skyBlockId - -object CustomGlobalArmorOverrides : SubscriptionOwner { - @Serializable - data class ArmorOverride( - @SerialName("item_ids") - val itemIds: List<String>, - val layers: List<ArmorOverrideLayer>, - val overrides: List<ArmorOverrideOverride> = listOf(), - ) { - @Transient - val bakedLayers = bakeLayers(layers) - } - - fun bakeLayers(layers: List<ArmorOverrideLayer>): List<ArmorMaterial.Layer> { - return layers.map { ArmorMaterial.Layer(it.identifier, it.suffix, it.tint) } - } - - @Serializable - data class ArmorOverrideLayer( - val tint: Boolean = false, - val identifier: Identifier, - val suffix: String = "", - ) - - @Serializable - data class ArmorOverrideOverride( - val predicate: FirmamentModelPredicate, - val layers: List<ArmorOverrideLayer>, - ) { - @Transient - val bakedLayers = bakeLayers(layers) - } - - override val delegateFeature: FirmamentFeature - get() = CustomSkyBlockTextures - - val overrideCache = mutableMapOf<IdentityCharacteristics<ItemStack>, Any>() - - @JvmStatic - fun overrideArmor(stack: ItemStack): List<ArmorMaterial.Layer>? { - if (!CustomSkyBlockTextures.TConfig.enableArmorOverrides) return null - return overrideCache.computeNullableFunction(IdentityCharacteristics(stack)) { - val id = stack.skyBlockId ?: return@computeNullableFunction null - val override = overrides[id.neuItem] ?: return@computeNullableFunction null - for (suboverride in override.overrides) { - if (suboverride.predicate.test(stack)) { - return@computeNullableFunction suboverride.bakedLayers - } - } - return@computeNullableFunction override.bakedLayers - } - } - - var overrides: Map<String, ArmorOverride> = mapOf() - - @Subscribe - fun onStart(event: FinalizeResourceManagerEvent) { - event.resourceManager.registerReloader(object : - SinglePreparationResourceReloader<Map<String, ArmorOverride>>() { - override fun prepare(manager: ResourceManager, profiler: Profiler): Map<String, ArmorOverride> { - val overrideFiles = manager.findResources("overrides/armor_models") { - it.namespace == "firmskyblock" && it.path.endsWith(".json") - } - val overrides = overrideFiles.mapNotNull { - Firmament.tryDecodeJsonFromStream<ArmorOverride>(it.value.inputStream).getOrElse { ex -> - logger.error("Failed to load armor texture override at ${it.key}", ex) - null - } - } - val associatedMap = overrides.flatMap { obj -> obj.itemIds.map { it to obj } } - .toMap() - return associatedMap - } - - override fun apply(prepared: Map<String, ArmorOverride>, manager: ResourceManager, profiler: Profiler) { - overrides = prepared - } - }) - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalTextures.kt deleted file mode 100644 index d64c844..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalTextures.kt +++ /dev/null @@ -1,167 +0,0 @@ - -@file:UseSerializers(IdentifierSerializer::class, CustomModelOverrideParser.FirmamentRootPredicateSerializer::class) - -package moe.nea.firmament.features.texturepack - - -import java.util.concurrent.CompletableFuture -import org.slf4j.LoggerFactory -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import kotlin.jvm.optionals.getOrNull -import net.minecraft.client.render.item.ItemModels -import net.minecraft.client.render.model.BakedModel -import net.minecraft.client.util.ModelIdentifier -import net.minecraft.item.ItemStack -import net.minecraft.resource.ResourceManager -import net.minecraft.resource.SinglePreparationResourceReloader -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import net.minecraft.util.profiler.Profiler -import moe.nea.firmament.Firmament -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.BakeExtraModelsEvent -import moe.nea.firmament.events.EarlyResourceReloadEvent -import moe.nea.firmament.events.FinalizeResourceManagerEvent -import moe.nea.firmament.events.ScreenChangeEvent -import moe.nea.firmament.events.subscription.SubscriptionOwner -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.util.IdentifierSerializer -import moe.nea.firmament.util.IdentityCharacteristics -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.computeNullableFunction -import moe.nea.firmament.util.json.SingletonSerializableList -import moe.nea.firmament.util.runNull - -object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalTextures.CustomGuiTextureOverride>(), - SubscriptionOwner { - override val delegateFeature: FirmamentFeature - get() = CustomSkyBlockTextures - - class CustomGuiTextureOverride( - val classes: List<ItemOverrideCollection> - ) - - @Serializable - data class GlobalItemOverride( - val screen: @Serializable(SingletonSerializableList::class) List<Identifier>, - val model: Identifier, - val predicate: FirmamentModelPredicate, - ) - - @Serializable - data class ScreenFilter( - val title: StringMatcher, - ) - - data class ItemOverrideCollection( - val screenFilter: ScreenFilter, - val overrides: List<GlobalItemOverride>, - ) - - @Subscribe - fun onStart(event: FinalizeResourceManagerEvent) { - MC.resourceManager.registerReloader(this) - } - - @Subscribe - fun onEarlyReload(event: EarlyResourceReloadEvent) { - preparationFuture = CompletableFuture - .supplyAsync( - { - prepare(event.resourceManager) - }, event.preparationExecutor) - } - - @Subscribe - fun onBakeModels(event: BakeExtraModelsEvent) { - for (guiClassOverride in preparationFuture.join().classes) { - for (override in guiClassOverride.overrides) { - event.addItemModel(ModelIdentifier(override.model, "inventory")) - } - } - } - - @Volatile - var preparationFuture: CompletableFuture<CustomGuiTextureOverride> = CompletableFuture.completedFuture( - CustomGuiTextureOverride(listOf())) - - override fun prepare(manager: ResourceManager?, profiler: Profiler?): CustomGuiTextureOverride { - return preparationFuture.join() - } - - override fun apply(prepared: CustomGuiTextureOverride, manager: ResourceManager?, profiler: Profiler?) { - this.guiClassOverrides = prepared - } - - val logger = LoggerFactory.getLogger(CustomGlobalTextures::class.java) - fun prepare(manager: ResourceManager): CustomGuiTextureOverride { - val overrideResources = - manager.findResources("overrides/item") { it.namespace == "firmskyblock" && it.path.endsWith(".json") } - .mapNotNull { - Firmament.tryDecodeJsonFromStream<GlobalItemOverride>(it.value.inputStream).getOrElse { ex -> - logger.error("Failed to load global item override at ${it.key}", ex) - null - } - } - - val byGuiClass = overrideResources.flatMap { override -> override.screen.toSet().map { it to override } } - .groupBy { it.first } - val guiClasses = byGuiClass.entries - .mapNotNull { - val key = it.key - val guiClassResource = - manager.getResource(Identifier.of(key.namespace, "filters/screen/${key.path}.json")) - .getOrNull() - ?: return@mapNotNull runNull { - logger.error("Failed to locate screen filter at $key") - } - val screenFilter = - Firmament.tryDecodeJsonFromStream<ScreenFilter>(guiClassResource.inputStream) - .getOrElse { ex -> - logger.error("Failed to load screen filter at $key", ex) - return@mapNotNull null - } - ItemOverrideCollection(screenFilter, it.value.map { it.second }) - } - logger.info("Loaded ${overrideResources.size} global item overrides") - return CustomGuiTextureOverride(guiClasses) - } - - var guiClassOverrides = CustomGuiTextureOverride(listOf()) - - var matchingOverrides: Set<ItemOverrideCollection> = setOf() - - @Subscribe - fun onOpenGui(event: ScreenChangeEvent) { - val newTitle = event.new?.title ?: Text.empty() - matchingOverrides = guiClassOverrides.classes - .filterTo(mutableSetOf()) { it.screenFilter.title.matches(newTitle) } - } - - val overrideCache = mutableMapOf<IdentityCharacteristics<ItemStack>, Any>() - - @JvmStatic - fun replaceGlobalModel( - models: ItemModels, - stack: ItemStack, - cir: CallbackInfoReturnable<BakedModel> - ) { - val value = overrideCache.computeNullableFunction(IdentityCharacteristics(stack)) { - for (guiClassOverride in matchingOverrides) { - for (override in guiClassOverride.overrides) { - if (override.predicate.test(stack)) { - return@computeNullableFunction models.modelManager.getModel( - ModelIdentifier(override.model, "inventory")) - } - } - } - null - } - if (value != null) - cir.returnValue = value - } - - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt deleted file mode 100644 index a4e7c02..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt +++ /dev/null @@ -1,74 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonObject -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import net.minecraft.item.ItemStack -import net.minecraft.util.Identifier - -object CustomModelOverrideParser { - object FirmamentRootPredicateSerializer : KSerializer<FirmamentModelPredicate> { - val delegateSerializer = kotlinx.serialization.json.JsonObject.serializer() - override val descriptor: SerialDescriptor - get() = SerialDescriptor("FirmamentModelRootPredicate", delegateSerializer.descriptor) - - override fun deserialize(decoder: Decoder): FirmamentModelPredicate { - val json = decoder.decodeSerializableValue(delegateSerializer).intoGson() as JsonObject - return AndPredicate(parsePredicates(json).toTypedArray()) - } - - override fun serialize(encoder: Encoder, value: FirmamentModelPredicate) { - TODO("Cannot serialize firmament predicates") - } - } - - val predicateParsers = mutableMapOf<Identifier, FirmamentModelPredicateParser>() - - - fun registerPredicateParser(name: String, parser: FirmamentModelPredicateParser) { - predicateParsers[Identifier.of("firmament", name)] = parser - } - - init { - registerPredicateParser("display_name", DisplayNamePredicate.Parser) - registerPredicateParser("lore", LorePredicate.Parser) - registerPredicateParser("all", AndPredicate.Parser) - registerPredicateParser("any", OrPredicate.Parser) - registerPredicateParser("not", NotPredicate.Parser) - registerPredicateParser("item", ItemPredicate.Parser) - registerPredicateParser("extra_attributes", ExtraAttributesPredicate.Parser) - registerPredicateParser("pet", PetPredicate.Parser) - } - - private val neverPredicate = listOf( - object : FirmamentModelPredicate { - override fun test(stack: ItemStack): Boolean { - return false - } - } - ) - - fun parsePredicates(predicates: JsonObject): List<FirmamentModelPredicate> { - val parsedPredicates = mutableListOf<FirmamentModelPredicate>() - for (predicateName in predicates.keySet()) { - if (!predicateName.startsWith("firmament:")) continue - val identifier = Identifier.of(predicateName) - val parser = predicateParsers[identifier] ?: return neverPredicate - val parsedPredicate = parser.parse(predicates[predicateName]) ?: return neverPredicate - parsedPredicates.add(parsedPredicate) - } - return parsedPredicates - } - - @JvmStatic - fun parseCustomModelOverrides(jsonObject: JsonObject): Array<FirmamentModelPredicate>? { - val predicates = (jsonObject["predicate"] as? JsonObject) ?: return null - val parsedPredicates = parsePredicates(predicates) - if (parsedPredicates.isEmpty()) - return null - return parsedPredicates.toTypedArray() - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt deleted file mode 100644 index dec6046..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt +++ /dev/null @@ -1,114 +0,0 @@ -package moe.nea.firmament.features.texturepack - -import com.mojang.authlib.minecraft.MinecraftProfileTexture -import com.mojang.authlib.properties.Property -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable -import net.minecraft.block.SkullBlock -import net.minecraft.client.MinecraftClient -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.util.ModelIdentifier -import net.minecraft.component.type.ProfileComponent -import net.minecraft.util.Identifier -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.BakeExtraModelsEvent -import moe.nea.firmament.events.CustomItemModelEvent -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.IdentityCharacteristics -import moe.nea.firmament.util.item.decodeProfileTextureProperty -import moe.nea.firmament.util.skyBlockId - -object CustomSkyBlockTextures : FirmamentFeature { - override val identifier: String - get() = "custom-skyblock-textures" - - object TConfig : ManagedConfig(identifier) { - val enabled by toggle("enabled") { true } - val skullsEnabled by toggle("skulls-enabled") { true } - val cacheDuration by integer("cache-duration", 0, 20) { 1 } - val enableModelOverrides by toggle("model-overrides") { true } - val enableArmorOverrides by toggle("armor-overrides") { true } - val enableBlockOverrides by toggle("block-overrides") { true } - } - - override val config: ManagedConfig - get() = TConfig - - @Subscribe - fun onTick(it: TickEvent) { - if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) { - // TODO: unify all of those caches somehow - CustomItemModelEvent.clearCache() - skullTextureCache.clear() - CustomGlobalTextures.overrideCache.clear() - CustomGlobalArmorOverrides.overrideCache.clear() - } - } - - @Subscribe - fun bakeCustomFirmModels(event: BakeExtraModelsEvent) { - val resources = - MinecraftClient.getInstance().resourceManager.findResources("models/item" - ) { it: Identifier -> - "firmskyblock" == it.namespace && it.path - .endsWith(".json") - } - for (identifier in resources.keys) { - val modelId = ModelIdentifier.ofInventoryVariant( - Identifier.of( - "firmskyblock", - identifier.path.substring( - "models/item/".length, - identifier.path.length - ".json".length), - )) - event.addItemModel(modelId) - } - } - - @Subscribe - fun onCustomModelId(it: CustomItemModelEvent) { - if (!TConfig.enabled) return - val id = it.itemStack.skyBlockId ?: return - it.overrideModel = ModelIdentifier.ofInventoryVariant(Identifier.of("firmskyblock", id.identifier.path)) - } - - private val skullTextureCache = mutableMapOf<IdentityCharacteristics<ProfileComponent>, Any>() - private val sentinelPresentInvalid = Object() - - private val mcUrlRegex = "https?://textures.minecraft.net/texture/([a-fA-F0-9]+)".toRegex() - - fun getSkullId(textureProperty: Property): String? { - val texture = decodeProfileTextureProperty(textureProperty) ?: return null - val textureUrl = - texture.textures[MinecraftProfileTexture.Type.SKIN]?.url ?: return null - val mcUrlData = mcUrlRegex.matchEntire(textureUrl) ?: return null - return mcUrlData.groupValues[1] - } - - fun getSkullTexture(profile: ProfileComponent): Identifier? { - val id = getSkullId(profile.properties["textures"].firstOrNull() ?: return null) ?: return null - return Identifier.of("firmskyblock", "textures/placedskull/$id.png") - } - - fun modifySkullTexture( - type: SkullBlock.SkullType?, - component: ProfileComponent?, - cir: CallbackInfoReturnable<RenderLayer> - ) { - if (type != SkullBlock.Type.PLAYER) return - if (!TConfig.skullsEnabled) return - if (component == null) return - val ic = IdentityCharacteristics(component) - - val n = skullTextureCache.getOrPut(ic) { - val id = getSkullTexture(component) ?: return@getOrPut sentinelPresentInvalid - if (!MinecraftClient.getInstance().resourceManager.getResource(id).isPresent) { - return@getOrPut sentinelPresentInvalid - } - return@getOrPut id - } - if (n === sentinelPresentInvalid) return - cir.returnValue = RenderLayer.getEntityTranslucent(n as Identifier) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt deleted file mode 100644 index c89931e..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt +++ /dev/null @@ -1,22 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NbtElement -import net.minecraft.nbt.NbtString -import moe.nea.firmament.util.item.displayNameAccordingToNbt -import moe.nea.firmament.util.item.loreAccordingToNbt - -data class DisplayNamePredicate(val stringMatcher: StringMatcher) : FirmamentModelPredicate { - override fun test(stack: ItemStack): Boolean { - val display = stack.displayNameAccordingToNbt - return stringMatcher.matches(display) - } - - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): FirmamentModelPredicate { - return DisplayNamePredicate(StringMatcher.parse(jsonElement)) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ExtraAttributesPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ExtraAttributesPredicate.kt deleted file mode 100644 index 4114f45..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/ExtraAttributesPredicate.kt +++ /dev/null @@ -1,268 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NbtByte -import net.minecraft.nbt.NbtCompound -import net.minecraft.nbt.NbtDouble -import net.minecraft.nbt.NbtElement -import net.minecraft.nbt.NbtFloat -import net.minecraft.nbt.NbtInt -import net.minecraft.nbt.NbtList -import net.minecraft.nbt.NbtLong -import net.minecraft.nbt.NbtShort -import net.minecraft.nbt.NbtString -import moe.nea.firmament.util.extraAttributes - -fun interface NbtMatcher { - fun matches(nbt: NbtElement): Boolean - - object Parser { - fun parse(jsonElement: JsonElement): NbtMatcher? { - if (jsonElement is JsonPrimitive) { - if (jsonElement.isString) { - val string = jsonElement.asString - return MatchStringExact(string) - } - if (jsonElement.isNumber) { - return MatchNumberExact(jsonElement.asLong) //TODO: parse generic number - } - } - if (jsonElement is JsonObject) { - var encounteredParser: NbtMatcher? = null - for (entry in ExclusiveParserType.entries) { - val data = jsonElement[entry.key] ?: continue - if (encounteredParser != null) { - // TODO: warn - return null - } - encounteredParser = entry.parse(data) ?: return null - } - return encounteredParser - } - return null - } - - enum class ExclusiveParserType(val key: String) { - STRING("string") { - override fun parse(element: JsonElement): NbtMatcher? { - return MatchString(StringMatcher.parse(element)) - } - }, - INT("int") { - override fun parse(element: JsonElement): NbtMatcher? { - return parseGenericNumber(element, - { it.asInt }, - { (it as? NbtInt)?.intValue() }, - { a, b -> - if (a == b) Comparison.EQUAL - else if (a < b) Comparison.LESS_THAN - else Comparison.GREATER - }) - } - }, - FLOAT("float") { - override fun parse(element: JsonElement): NbtMatcher? { - return parseGenericNumber(element, - { it.asFloat }, - { (it as? NbtFloat)?.floatValue() }, - { a, b -> - if (a == b) Comparison.EQUAL - else if (a < b) Comparison.LESS_THAN - else Comparison.GREATER - }) - } - }, - DOUBLE("double") { - override fun parse(element: JsonElement): NbtMatcher? { - return parseGenericNumber(element, - { it.asDouble }, - { (it as? NbtDouble)?.doubleValue() }, - { a, b -> - if (a == b) Comparison.EQUAL - else if (a < b) Comparison.LESS_THAN - else Comparison.GREATER - }) - } - }, - LONG("long") { - override fun parse(element: JsonElement): NbtMatcher? { - return parseGenericNumber(element, - { it.asLong }, - { (it as? NbtLong)?.longValue() }, - { a, b -> - if (a == b) Comparison.EQUAL - else if (a < b) Comparison.LESS_THAN - else Comparison.GREATER - }) - } - }, - SHORT("short") { - override fun parse(element: JsonElement): NbtMatcher? { - return parseGenericNumber(element, - { it.asShort }, - { (it as? NbtShort)?.shortValue() }, - { a, b -> - if (a == b) Comparison.EQUAL - else if (a < b) Comparison.LESS_THAN - else Comparison.GREATER - }) - } - }, - BYTE("byte") { - override fun parse(element: JsonElement): NbtMatcher? { - return parseGenericNumber(element, - { it.asByte }, - { (it as? NbtByte)?.byteValue() }, - { a, b -> - if (a == b) Comparison.EQUAL - else if (a < b) Comparison.LESS_THAN - else Comparison.GREATER - }) - } - }, - ; - - abstract fun parse(element: JsonElement): NbtMatcher? - } - - enum class Comparison { - LESS_THAN, EQUAL, GREATER - } - - inline fun <T : Any> parseGenericNumber( - jsonElement: JsonElement, - primitiveExtractor: (JsonPrimitive) -> T?, - crossinline nbtExtractor: (NbtElement) -> T?, - crossinline compare: (T, T) -> Comparison - ): NbtMatcher? { - if (jsonElement is JsonPrimitive) { - val expected = primitiveExtractor(jsonElement) ?: return null - return NbtMatcher { - val actual = nbtExtractor(it) ?: return@NbtMatcher false - compare(actual, expected) == Comparison.EQUAL - } - } - if (jsonElement is JsonObject) { - val minElement = jsonElement.getAsJsonPrimitive("min") - val min = if (minElement != null) primitiveExtractor(minElement) ?: return null else null - val minExclusive = jsonElement.get("minExclusive")?.asBoolean ?: false - val maxElement = jsonElement.getAsJsonPrimitive("max") - val max = if (maxElement != null) primitiveExtractor(maxElement) ?: return null else null - val maxExclusive = jsonElement.get("maxExclusive")?.asBoolean ?: true - if (min == null && max == null) return null - return NbtMatcher { - val actual = nbtExtractor(it) ?: return@NbtMatcher false - if (max != null) { - val comp = compare(actual, max) - if (comp == Comparison.GREATER) return@NbtMatcher false - if (comp == Comparison.EQUAL && maxExclusive) return@NbtMatcher false - } - if (min != null) { - val comp = compare(actual, min) - if (comp == Comparison.LESS_THAN) return@NbtMatcher false - if (comp == Comparison.EQUAL && minExclusive) return@NbtMatcher false - } - return@NbtMatcher true - } - } - return null - - } - } - - class MatchNumberExact(val number: Long) : NbtMatcher { - override fun matches(nbt: NbtElement): Boolean { - return when (nbt) { - is NbtByte -> nbt.byteValue().toLong() == number - is NbtInt -> nbt.intValue().toLong() == number - is NbtShort -> nbt.shortValue().toLong() == number - is NbtLong -> nbt.longValue().toLong() == number - else -> false - } - } - - } - - class MatchStringExact(val string: String) : NbtMatcher { - override fun matches(nbt: NbtElement): Boolean { - return nbt is NbtString && nbt.asString() == string - } - - override fun toString(): String { - return "MatchNbtStringExactly($string)" - } - } - - class MatchString(val string: StringMatcher) : NbtMatcher { - override fun matches(nbt: NbtElement): Boolean { - return nbt is NbtString && string.matches(nbt.asString()) - } - - override fun toString(): String { - return "MatchNbtString($string)" - } - } -} - -data class ExtraAttributesPredicate( - val path: NbtPrism, - val matcher: NbtMatcher, -) : FirmamentModelPredicate { - - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): FirmamentModelPredicate? { - if (jsonElement !is JsonObject) return null - val path = jsonElement.get("path") ?: return null - val pathSegments = if (path is JsonArray) { - path.map { (it as JsonPrimitive).asString } - } else if (path is JsonPrimitive && path.isString) { - path.asString.split(".") - } else return null - val matcher = NbtMatcher.Parser.parse(jsonElement.get("match") ?: jsonElement) - ?: return null - return ExtraAttributesPredicate(NbtPrism(pathSegments), matcher) - } - } - - override fun test(stack: ItemStack): Boolean { - return path.access(stack.extraAttributes) - .any { matcher.matches(it) } - } -} - -class NbtPrism(val path: List<String>) { - override fun toString(): String { - return "Prism($path)" - } - fun access(root: NbtElement): Collection<NbtElement> { - var rootSet = mutableListOf(root) - var switch = mutableListOf<NbtElement>() - for (pathSegment in path) { - if (pathSegment == ".") continue - for (element in rootSet) { - if (element is NbtList) { - if (pathSegment == "*") - switch.addAll(element) - val index = pathSegment.toIntOrNull() ?: continue - if (index !in element.indices) continue - switch.add(element[index]) - } - if (element is NbtCompound) { - if (pathSegment == "*") - element.keys.mapTo(switch) { element.get(it)!! } - switch.add(element.get(pathSegment) ?: continue) - } - } - val temp = switch - switch = rootSet - rootSet = temp - switch.clear() - } - return rootSet - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt deleted file mode 100644 index d11fec0..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt +++ /dev/null @@ -1,8 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import net.minecraft.item.ItemStack - -interface FirmamentModelPredicate { - fun test(stack: ItemStack): Boolean -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicateParser.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicateParser.kt deleted file mode 100644 index 3ed0c67..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicateParser.kt +++ /dev/null @@ -1,8 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement - -interface FirmamentModelPredicateParser { - fun parse(jsonElement: JsonElement): FirmamentModelPredicate? -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ItemPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ItemPredicate.kt deleted file mode 100644 index 4302b53..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/ItemPredicate.kt +++ /dev/null @@ -1,32 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import com.google.gson.JsonPrimitive -import kotlin.jvm.optionals.getOrNull -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.registry.RegistryKey -import net.minecraft.registry.RegistryKeys -import net.minecraft.util.Identifier -import moe.nea.firmament.util.MC - -class ItemPredicate( - val item: Item -) : FirmamentModelPredicate { - override fun test(stack: ItemStack): Boolean { - return stack.item == item - } - - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): ItemPredicate? { - if (jsonElement is JsonPrimitive && jsonElement.isString) { - val itemKey = RegistryKey.of(RegistryKeys.ITEM, - Identifier.tryParse(jsonElement.asString) - ?: return null) - return ItemPredicate(MC.defaultItems.getOptional(itemKey).getOrNull()?.value() ?: return null) - } - return null - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/JsonUnbakedModelFirmExtra.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/JsonUnbakedModelFirmExtra.kt deleted file mode 100644 index ab9e27d..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/JsonUnbakedModelFirmExtra.kt +++ /dev/null @@ -1,10 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import net.minecraft.util.Identifier - -interface JsonUnbakedModelFirmExtra { - - fun setHeadModel_firmament(identifier: Identifier?) - fun getHeadModel_firmament(): Identifier? -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt deleted file mode 100644 index 13e3974..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt +++ /dev/null @@ -1,19 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import net.minecraft.item.ItemStack -import moe.nea.firmament.util.item.loreAccordingToNbt - -class LorePredicate(val matcher: StringMatcher) : FirmamentModelPredicate { - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): FirmamentModelPredicate { - return LorePredicate(StringMatcher.parse(jsonElement)) - } - } - - override fun test(stack: ItemStack): Boolean { - val lore = stack.loreAccordingToNbt - return lore.any { matcher.matches(it) } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt deleted file mode 100644 index 1585bd7..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt +++ /dev/null @@ -1,7 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -interface ModelOverrideData { - fun getFirmamentOverrides(): Array<FirmamentModelPredicate>? - fun setFirmamentOverrides(overrides: Array<FirmamentModelPredicate>?) -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideFilterSet.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideFilterSet.kt deleted file mode 100644 index 4ef8d06..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideFilterSet.kt +++ /dev/null @@ -1,19 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import moe.nea.firmament.util.filter.IteratorFilterSet - -class ModelOverrideFilterSet(original: java.util.Set<Map.Entry<String, JsonElement>>) : - IteratorFilterSet<Map.Entry<String, JsonElement>>(original) { - companion object { - @JvmStatic - fun createFilterSet(set: java.util.Set<*>): java.util.Set<*> { - return ModelOverrideFilterSet(set as java.util.Set<Map.Entry<String, JsonElement>>) as java.util.Set<*> - } - } - - override fun shouldKeepElement(element: Map.Entry<String, JsonElement>): Boolean { - return !element.key.startsWith("firmament:") - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/NotPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/NotPredicate.kt deleted file mode 100644 index ecd67c3..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/NotPredicate.kt +++ /dev/null @@ -1,18 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import net.minecraft.item.ItemStack - -class NotPredicate(val children: Array<FirmamentModelPredicate>) : FirmamentModelPredicate { - override fun test(stack: ItemStack): Boolean { - return children.none { it.test(stack) } - } - - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): FirmamentModelPredicate { - return NotPredicate(CustomModelOverrideParser.parsePredicates(jsonElement as JsonObject).toTypedArray()) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/NumberMatcher.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/NumberMatcher.kt deleted file mode 100644 index 7e6665f..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/NumberMatcher.kt +++ /dev/null @@ -1,125 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import com.google.gson.JsonPrimitive -import moe.nea.firmament.util.useMatch - -abstract class NumberMatcher { - abstract fun test(number: Number): Boolean - - - companion object { - fun parse(jsonElement: JsonElement): NumberMatcher? { - if (jsonElement is JsonPrimitive) { - if (jsonElement.isString) { - val string = jsonElement.asString - return parseRange(string) ?: parseOperator(string) - } - if (jsonElement.isNumber) { - val number = jsonElement.asNumber - val hasDecimals = (number.toString().contains(".")) - return MatchNumberExact(if (hasDecimals) number.toLong() else number.toDouble()) - } - } - return null - } - - private val intervalSpec = - "(?<beginningOpen>[\\[\\(])(?<beginning>[0-9.]+)?,(?<ending>[0-9.]+)?(?<endingOpen>[\\]\\)])" - .toPattern() - - fun parseRange(string: String): RangeMatcher? { - intervalSpec.useMatch<Nothing>(string) { - // Open in the set-theory sense, meaning does not include its end. - val beginningOpen = group("beginningOpen") == "(" - val endingOpen = group("endingOpen") == ")" - val beginning = group("beginning")?.toDouble() - val ending = group("ending")?.toDouble() - return RangeMatcher(beginning, !beginningOpen, ending, !endingOpen) - } - return null - } - - enum class Operator(val operator: String) { - LESS("<") { - override fun matches(comparisonResult: Int): Boolean { - return comparisonResult < 0 - } - }, - LESS_EQUALS("<=") { - override fun matches(comparisonResult: Int): Boolean { - return comparisonResult <= 0 - } - }, - GREATER(">") { - override fun matches(comparisonResult: Int): Boolean { - return comparisonResult > 0 - } - }, - GREATER_EQUALS(">=") { - override fun matches(comparisonResult: Int): Boolean { - return comparisonResult >= 0 - } - }, - ; - - abstract fun matches(comparisonResult: Int): Boolean - } - - private val operatorPattern = "(?<operator>${Operator.entries.joinToString("|") {it.operator}})(?<value>[0-9.]+)".toPattern() - - fun parseOperator(string: String): OperatorMatcher? { - operatorPattern.useMatch<Nothing>(string) { - val operatorName = group("operator") - val operator = Operator.entries.find { it.operator == operatorName }!! - val value = group("value").toDouble() - return OperatorMatcher(operator, value) - } - return null - } - - data class OperatorMatcher(val operator: Operator, val value: Double) : NumberMatcher() { - override fun test(number: Number): Boolean { - return operator.matches(number.toDouble().compareTo(value)) - } - } - - - data class MatchNumberExact(val number: Number) : NumberMatcher() { - override fun test(number: Number): Boolean { - return when (this.number) { - is Double -> number.toDouble() == this.number.toDouble() - else -> number.toLong() == this.number.toLong() - } - } - } - - data class RangeMatcher( - val beginning: Double?, - val beginningInclusive: Boolean, - val ending: Double?, - val endingInclusive: Boolean, - ) : NumberMatcher() { - override fun test(number: Number): Boolean { - val value = number.toDouble() - if (beginning != null) { - if (beginningInclusive) { - if (value < beginning) return false - } else { - if (value <= beginning) return false - } - } - if (ending != null) { - if (endingInclusive) { - if (value > ending) return false - } else { - if (value >= ending) return false - } - } - return true - } - } - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt deleted file mode 100644 index 32f556b..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt +++ /dev/null @@ -1,26 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import net.minecraft.item.ItemStack - -class OrPredicate(val children: Array<FirmamentModelPredicate>) : FirmamentModelPredicate { - override fun test(stack: ItemStack): Boolean { - return children.any { it.test(stack) } - } - - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): FirmamentModelPredicate { - val children = - (jsonElement as JsonArray) - .flatMap { - CustomModelOverrideParser.parsePredicates(it as JsonObject) - } - .toTypedArray() - return OrPredicate(children) - } - - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/PetPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/PetPredicate.kt deleted file mode 100644 index 5e5d750..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/PetPredicate.kt +++ /dev/null @@ -1,66 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import net.minecraft.item.ItemStack -import moe.nea.firmament.repo.ExpLadders -import moe.nea.firmament.util.petData - -class PetPredicate( - val petId: StringMatcher?, - val tier: RarityMatcher?, - val exp: NumberMatcher?, - val candyUsed: NumberMatcher?, - val level: NumberMatcher?, -) : FirmamentModelPredicate { - - override fun test(stack: ItemStack): Boolean { - val petData = stack.petData ?: return false - if (petId != null) { - if (!petId.matches(petData.type)) return false - } - if (exp != null) { - if (!exp.test(petData.exp)) return false - } - if (candyUsed != null) { - if (!candyUsed.test(petData.candyUsed)) return false - } - if (tier != null) { - if (!tier.match(petData.tier)) return false - } - val levelData by lazy(LazyThreadSafetyMode.NONE) { - ExpLadders.getExpLadder(petData.type, petData.tier) - .getPetLevel(petData.exp) - } - if (level != null) { - if (!level.test(levelData.currentLevel)) return false - } - return true - } - - object Parser : FirmamentModelPredicateParser { - override fun parse(jsonElement: JsonElement): FirmamentModelPredicate? { - if (jsonElement.isJsonPrimitive) { - return PetPredicate(StringMatcher.Equals(jsonElement.asString, false), null, null, null, null) - } - if (jsonElement !is JsonObject) return null - val idMatcher = jsonElement["id"]?.let(StringMatcher::parse) - val expMatcher = jsonElement["exp"]?.let(NumberMatcher::parse) - val levelMatcher = jsonElement["level"]?.let(NumberMatcher::parse) - val candyMatcher = jsonElement["candyUsed"]?.let(NumberMatcher::parse) - val tierMatcher = jsonElement["tier"]?.let(RarityMatcher::parse) - return PetPredicate( - idMatcher, - tierMatcher, - expMatcher, - candyMatcher, - levelMatcher, - ) - } - } - - override fun toString(): String { - return super.toString() - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/RarityMatcher.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/RarityMatcher.kt deleted file mode 100644 index 634a171..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/RarityMatcher.kt +++ /dev/null @@ -1,69 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import io.github.moulberry.repo.data.Rarity -import moe.nea.firmament.util.useMatch - -abstract class RarityMatcher { - abstract fun match(rarity: Rarity): Boolean - - companion object { - fun parse(jsonElement: JsonElement): RarityMatcher { - val string = jsonElement.asString - val range = parseRange(string) - if (range != null) return range - return Exact(Rarity.valueOf(string)) - } - - private val allRarities = Rarity.entries.joinToString("|", "(?:", ")") - private val intervalSpec = - "(?<beginningOpen>[\\[\\(])(?<beginning>$allRarities)?,(?<ending>$allRarities)?(?<endingOpen>[\\]\\)])" - .toPattern() - - fun parseRange(string: String): RangeMatcher? { - intervalSpec.useMatch<Nothing>(string) { - // Open in the set-theory sense, meaning does not include its end. - val beginningOpen = group("beginningOpen") == "(" - val endingOpen = group("endingOpen") == ")" - val beginning = group("beginning")?.let(Rarity::valueOf) - val ending = group("ending")?.let(Rarity::valueOf) - return RangeMatcher(beginning, !beginningOpen, ending, !endingOpen) - } - return null - } - - } - - data class Exact(val expected: Rarity) : RarityMatcher() { - override fun match(rarity: Rarity): Boolean { - return rarity == expected - } - } - - data class RangeMatcher( - val beginning: Rarity?, - val beginningInclusive: Boolean, - val ending: Rarity?, - val endingInclusive: Boolean, - ) : RarityMatcher() { - override fun match(rarity: Rarity): Boolean { - if (beginning != null) { - if (beginningInclusive) { - if (rarity < beginning) return false - } else { - if (rarity <= beginning) return false - } - } - if (ending != null) { - if (endingInclusive) { - if (rarity > ending) return false - } else { - if (rarity >= ending) return false - } - } - return true - } - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt deleted file mode 100644 index 5eb86ac..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt +++ /dev/null @@ -1,159 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonNull -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import com.google.gson.internal.LazilyParsedNumber -import java.util.function.Predicate -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import net.minecraft.nbt.NbtString -import net.minecraft.text.Text -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.removeColorCodes - -@Serializable(with = StringMatcher.Serializer::class) -interface StringMatcher { - fun matches(string: String): Boolean - fun matches(text: Text): Boolean { - return matches(text.string) - } - - fun matches(nbt: NbtString): Boolean { - val string = nbt.asString() - val jsonStart = string.indexOf('{') - val stringStart = string.indexOf('"') - val isString = stringStart >= 0 && string.subSequence(0, stringStart).isBlank() - val isJson = jsonStart >= 0 && string.subSequence(0, jsonStart).isBlank() - if (isString || isJson) - return matches(Text.Serialization.fromJson(string, MC.defaultRegistries) ?: return false) - return matches(string) - } - - class Equals(input: String, val stripColorCodes: Boolean) : StringMatcher { - private val expected = if (stripColorCodes) input.removeColorCodes() else input - override fun matches(string: String): Boolean { - return expected == (if (stripColorCodes) string.removeColorCodes() else string) - } - - override fun toString(): String { - return "Equals($expected, stripColorCodes = $stripColorCodes)" - } - } - - class Pattern(val patternWithColorCodes: String, val stripColorCodes: Boolean) : StringMatcher { - private val regex: Predicate<String> = patternWithColorCodes.toPattern().asMatchPredicate() - override fun matches(string: String): Boolean { - return regex.test(if (stripColorCodes) string.removeColorCodes() else string) - } - - override fun toString(): String { - return "Pattern($patternWithColorCodes, stripColorCodes = $stripColorCodes)" - } - } - - object Serializer : KSerializer<StringMatcher> { - val delegateSerializer = kotlinx.serialization.json.JsonElement.serializer() - override val descriptor: SerialDescriptor - get() = SerialDescriptor("StringMatcher", delegateSerializer.descriptor) - - override fun deserialize(decoder: Decoder): StringMatcher { - val delegate = decoder.decodeSerializableValue(delegateSerializer) - val gsonDelegate = delegate.intoGson() - return parse(gsonDelegate) - } - - override fun serialize(encoder: Encoder, value: StringMatcher) { - encoder.encodeSerializableValue(delegateSerializer, Companion.serialize(value).intoKotlinJson()) - } - - } - - companion object { - fun serialize(stringMatcher: StringMatcher): JsonElement { - TODO("Cannot serialize string matchers rn") - } - - fun parse(jsonElement: JsonElement): StringMatcher { - if (jsonElement is JsonPrimitive) { - return Equals(jsonElement.asString, true) - } - if (jsonElement is JsonObject) { - val regex = jsonElement["regex"] as JsonPrimitive? - val text = jsonElement["equals"] as JsonPrimitive? - val shouldStripColor = when (val color = (jsonElement["color"] as JsonPrimitive?)?.asString) { - "preserve" -> false - "strip", null -> true - else -> error("Unknown color preservation mode: $color") - } - if ((regex == null) == (text == null)) error("Could not parse $jsonElement as string matcher") - if (regex != null) - return Pattern(regex.asString, shouldStripColor) - if (text != null) - return Equals(text.asString, shouldStripColor) - } - error("Could not parse $jsonElement as a string matcher") - } - } -} - -fun JsonElement.intoKotlinJson(): kotlinx.serialization.json.JsonElement { - when (this) { - is JsonNull -> return kotlinx.serialization.json.JsonNull - is JsonObject -> { - return kotlinx.serialization.json.JsonObject(this.entrySet() - .associate { it.key to it.value.intoKotlinJson() }) - } - - is JsonArray -> { - return kotlinx.serialization.json.JsonArray(this.map { it.intoKotlinJson() }) - } - - is JsonPrimitive -> { - if (this.isString) - return kotlinx.serialization.json.JsonPrimitive(this.asString) - if (this.isBoolean) - return kotlinx.serialization.json.JsonPrimitive(this.asBoolean) - return kotlinx.serialization.json.JsonPrimitive(this.asNumber) - } - - else -> error("Unknown json variant $this") - } -} - -fun kotlinx.serialization.json.JsonElement.intoGson(): JsonElement { - when (this) { - is kotlinx.serialization.json.JsonNull -> return JsonNull.INSTANCE - is kotlinx.serialization.json.JsonPrimitive -> { - if (this.isString) - return JsonPrimitive(this.content) - if (this.content == "true") - return JsonPrimitive(true) - if (this.content == "false") - return JsonPrimitive(false) - return JsonPrimitive(LazilyParsedNumber(this.content)) - } - - is kotlinx.serialization.json.JsonObject -> { - val obj = JsonObject() - for ((k, v) in this) { - obj.add(k, v.intoGson()) - } - return obj - } - - is kotlinx.serialization.json.JsonArray -> { - val arr = JsonArray() - for (v in this) { - arr.add(v.intoGson()) - } - return arr - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt b/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt deleted file mode 100644 index 8a8291a..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/world/FairySouls.kt +++ /dev/null @@ -1,131 +0,0 @@ - - -package moe.nea.firmament.features.world - -import io.github.moulberry.repo.data.Coordinate -import kotlinx.serialization.Serializable -import kotlinx.serialization.serializer -import net.minecraft.text.Text -import net.minecraft.util.math.Vec3d -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.SkyblockServerUpdateEvent -import moe.nea.firmament.events.WorldRenderLastEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SBData -import moe.nea.firmament.util.SkyBlockIsland -import moe.nea.firmament.util.blockPos -import moe.nea.firmament.util.data.ProfileSpecificDataHolder -import moe.nea.firmament.util.render.RenderInWorldContext -import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld -import moe.nea.firmament.util.unformattedString - - -object FairySouls : FirmamentFeature { - - - @Serializable - data class Data( - val foundSouls: MutableMap<SkyBlockIsland, MutableSet<Int>> = mutableMapOf() - ) - - override val config: ManagedConfig - get() = TConfig - - object DConfig : ProfileSpecificDataHolder<Data>(serializer(), "found-fairysouls", ::Data) - - - object TConfig : ManagedConfig("fairy-souls") { - val displaySouls by toggle("show") { false } - val resetSouls by button("reset") { - DConfig.data?.foundSouls?.clear() != null - updateMissingSouls() - } - } - - - override val identifier: String get() = "fairy-souls" - - val playerReach = 5 - val playerReachSquared = playerReach * playerReach - - var currentLocationName: SkyBlockIsland? = null - var currentLocationSouls: List<Coordinate> = emptyList() - var currentMissingSouls: List<Coordinate> = emptyList() - - fun updateMissingSouls() { - currentMissingSouls = emptyList() - val c = DConfig.data ?: return - val fi = c.foundSouls[currentLocationName] ?: setOf() - val cms = currentLocationSouls.toMutableList() - fi.asSequence().sortedDescending().filter { it in cms.indices }.forEach { cms.removeAt(it) } - currentMissingSouls = cms - } - - fun updateWorldSouls() { - currentLocationSouls = emptyList() - val loc = currentLocationName ?: return - currentLocationSouls = RepoManager.neuRepo.constants.fairySouls.soulLocations[loc.locrawMode] ?: return - } - - fun findNearestClickableSoul(): Coordinate? { - val player = MC.player ?: return null - val pos = player.pos - val location = SBData.skyblockLocation ?: return null - val soulLocations: List<Coordinate> = - RepoManager.neuRepo.constants.fairySouls.soulLocations[location.locrawMode] ?: return null - return soulLocations - .map { it to it.blockPos.getSquaredDistance(pos) } - .filter { it.second < playerReachSquared } - .minByOrNull { it.second } - ?.first - } - - private fun markNearestSoul() { - val nearestSoul = findNearestClickableSoul() ?: return - val c = DConfig.data ?: return - val loc = currentLocationName ?: return - val idx = currentLocationSouls.indexOf(nearestSoul) - c.foundSouls.computeIfAbsent(loc) { mutableSetOf() }.add(idx) - DConfig.markDirty() - updateMissingSouls() - } - - @Subscribe - fun onWorldRender(it: WorldRenderLastEvent) { - if (!TConfig.displaySouls) return - renderInWorld(it) { - color(1F, 1F, 0F, 0.8F) - currentMissingSouls.forEach { - block(it.blockPos) - } - color(1f, 0f, 1f, 1f) - currentLocationSouls.forEach { - wireframeCube(it.blockPos) - } - } - } - - @Subscribe - fun onProcessChat(it: ProcessChatEvent) { - when (it.text.unformattedString) { - "You have already found that Fairy Soul!" -> { - markNearestSoul() - } - - "SOUL! You found a Fairy Soul!" -> { - markNearestSoul() - } - } - } - - @Subscribe - fun onLocationChange(it: SkyblockServerUpdateEvent) { - currentLocationName = it.newLocraw?.skyblockLocation - updateWorldSouls() - updateMissingSouls() - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/NPCWaypoints.kt b/src/main/kotlin/moe/nea/firmament/features/world/NPCWaypoints.kt deleted file mode 100644 index 592b8fa..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/world/NPCWaypoints.kt +++ /dev/null @@ -1,40 +0,0 @@ -package moe.nea.firmament.features.world - -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.commands.thenExecute -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.events.ReloadRegistrationEvent -import moe.nea.firmament.util.MoulConfigUtils -import moe.nea.firmament.util.ScreenUtil - -object NPCWaypoints { - - var allNpcWaypoints = listOf<NavigableWaypoint>() - - @Subscribe - fun onRepoReloadRegistration(event: ReloadRegistrationEvent) { - event.repo.registerReloadListener { - allNpcWaypoints = it.items.items.values - .asSequence() - .filter { !it.island.isNullOrBlank() } - .map { - NavigableWaypoint.NPCWaypoint(it) - } - .toList() - } - } - - @Subscribe - fun onOpenGui(event: CommandEvent.SubCommand) { - event.subcommand("npcs") { - thenExecute { - ScreenUtil.setScreenLater(MoulConfigUtils.loadScreen( - "npc_waypoints", - NpcWaypointGui(allNpcWaypoints), - null)) - } - } - } - - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/NavigableWaypoint.kt b/src/main/kotlin/moe/nea/firmament/features/world/NavigableWaypoint.kt deleted file mode 100644 index 28a517f..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/world/NavigableWaypoint.kt +++ /dev/null @@ -1,22 +0,0 @@ -package moe.nea.firmament.features.world - -import io.github.moulberry.repo.data.NEUItem -import net.minecraft.util.math.BlockPos -import moe.nea.firmament.util.SkyBlockIsland - -abstract class NavigableWaypoint { - abstract val name: String - abstract val position: BlockPos - abstract val island: SkyBlockIsland - - data class NPCWaypoint( - val item: NEUItem, - ) : NavigableWaypoint() { - override val name: String - get() = item.displayName - override val position: BlockPos - get() = BlockPos(item.x, item.y, item.z) - override val island: SkyBlockIsland - get() = SkyBlockIsland.forMode(item.island) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/NavigationHelper.kt b/src/main/kotlin/moe/nea/firmament/features/world/NavigationHelper.kt deleted file mode 100644 index acdfb86..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/world/NavigationHelper.kt +++ /dev/null @@ -1,121 +0,0 @@ -package moe.nea.firmament.features.world - -import io.github.moulberry.repo.constants.Islands -import net.minecraft.text.Text -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Position -import net.minecraft.util.math.Vec3i -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.SkyblockServerUpdateEvent -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.events.WorldRenderLastEvent -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SBData -import moe.nea.firmament.util.SkyBlockIsland -import moe.nea.firmament.util.WarpUtil -import moe.nea.firmament.util.render.RenderInWorldContext - -object NavigationHelper { - var targetWaypoint: NavigableWaypoint? = null - set(value) { - field = value - recalculateRoute() - } - - var nextTeleporter: Islands.Teleporter? = null - private set - - val Islands.Teleporter.toIsland get() = SkyBlockIsland.forMode(this.getTo()) - val Islands.Teleporter.fromIsland get() = SkyBlockIsland.forMode(this.getFrom()) - val Islands.Teleporter.blockPos get() = BlockPos(x.toInt(), y.toInt(), z.toInt()) - - @Subscribe - fun onWorldSwitch(event: SkyblockServerUpdateEvent) { - recalculateRoute() - } - - fun recalculateRoute() { - val tp = targetWaypoint - val currentIsland = SBData.skyblockLocation - if (tp == null || currentIsland == null) { - nextTeleporter = null - return - } - val route = findRoute(currentIsland, tp.island, mutableSetOf()) - nextTeleporter = route?.get(0) - } - - private fun findRoute( - fromIsland: SkyBlockIsland, - targetIsland: SkyBlockIsland, - visitedIslands: MutableSet<SkyBlockIsland> - ): MutableList<Islands.Teleporter>? { - var shortestChain: MutableList<Islands.Teleporter>? = null - for (it in RepoManager.neuRepo.constants.islands.teleporters) { - if (it.toIsland in visitedIslands) continue - if (it.fromIsland != fromIsland) continue - if (it.toIsland == targetIsland) return mutableListOf(it) - visitedIslands.add(fromIsland) - val nextRoute = findRoute(it.toIsland, targetIsland, visitedIslands) ?: continue - nextRoute.add(0, it) - if (shortestChain == null || shortestChain.size > nextRoute.size) { - shortestChain = nextRoute - } - visitedIslands.remove(fromIsland) - } - return shortestChain - } - - - @Subscribe - fun onMovement(event: TickEvent) { // TODO: add a movement tick event maybe? - val tp = targetWaypoint ?: return - val p = MC.player ?: return - if (p.squaredDistanceTo(tp.position.toCenterPos()) < 5 * 5) { - targetWaypoint = null - } - } - - @Subscribe - fun drawWaypoint(event: WorldRenderLastEvent) { - val tp = targetWaypoint ?: return - val nt = nextTeleporter - RenderInWorldContext.renderInWorld(event) { - if (nt != null) { - waypoint(nt.blockPos, - Text.literal("Teleporter to " + nt.toIsland.userFriendlyName), - Text.literal("(towards " + tp.name + "§f)")) - } else if (tp.island == SBData.skyblockLocation) { - waypoint(tp.position, - Text.literal(tp.name)) - } - } - } - - fun tryWarpNear() { - val tp = targetWaypoint - if (tp == null) { - MC.sendChat(Text.literal("Could not find a waypoint to warp you to. Select one first.")) - return - } - WarpUtil.teleportToNearestWarp(tp.island, tp.position.asPositionView()) - } - -} - -fun Vec3i.asPositionView(): Position { - return object : Position { - override fun getX(): Double { - return this@asPositionView.x.toDouble() - } - - override fun getY(): Double { - return this@asPositionView.y.toDouble() - } - - override fun getZ(): Double { - return this@asPositionView.z.toDouble() - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/NpcWaypointGui.kt b/src/main/kotlin/moe/nea/firmament/features/world/NpcWaypointGui.kt deleted file mode 100644 index 6146e50..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/world/NpcWaypointGui.kt +++ /dev/null @@ -1,68 +0,0 @@ -package moe.nea.firmament.features.world - -import io.github.notenoughupdates.moulconfig.observer.ObservableList -import io.github.notenoughupdates.moulconfig.xml.Bind -import moe.nea.firmament.features.events.anniversity.AnniversaryFeatures.atOnce -import moe.nea.firmament.keybindings.SavedKeyBinding - -class NpcWaypointGui( - val allWaypoints: List<NavigableWaypoint>, -) { - - data class NavigableWaypointW(val waypoint: NavigableWaypoint) { - @Bind - fun name() = waypoint.name - - @Bind - fun isSelected() = NavigationHelper.targetWaypoint == waypoint - - @Bind - fun click() { - if (SavedKeyBinding.isShiftDown()) { - NavigationHelper.targetWaypoint = waypoint - NavigationHelper.tryWarpNear() - } else if (isSelected()) { - NavigationHelper.targetWaypoint = null - } else { - NavigationHelper.targetWaypoint = waypoint - } - } - } - - @JvmField - @field:Bind - var search: String = "" - var lastSearch: String? = null - - @Bind("results") - fun results(): ObservableList<NavigableWaypointW> { - return results - } - - @Bind - fun tick() { - if (search != lastSearch) { - updateSearch() - lastSearch = search - } - } - - val results: ObservableList<NavigableWaypointW> = ObservableList(mutableListOf()) - - fun updateSearch() { - val split = search.split(" +".toRegex()) - results.atOnce { - results.clear() - allWaypoints.filter { waypoint -> - if (search.isBlank()) { - true - } else { - split.all { waypoint.name.contains(it, ignoreCase = true) } - } - }.mapTo(results) { - NavigableWaypointW(it) - } - } - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt b/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt deleted file mode 100644 index 91a06da..0000000 --- a/src/main/kotlin/moe/nea/firmament/features/world/Waypoints.kt +++ /dev/null @@ -1,297 +0,0 @@ - - -package moe.nea.firmament.features.world - -import com.mojang.brigadier.arguments.IntegerArgumentType -import me.shedaniel.math.Color -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource -import kotlinx.serialization.Serializable -import kotlin.collections.component1 -import kotlin.collections.component2 -import kotlin.collections.set -import kotlin.time.Duration.Companion.hours -import kotlin.time.Duration.Companion.seconds -import net.minecraft.command.argument.BlockPosArgumentType -import net.minecraft.server.command.ServerCommandSource -import net.minecraft.text.Text -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Vec3d -import moe.nea.firmament.Firmament -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.commands.get -import moe.nea.firmament.commands.thenArgument -import moe.nea.firmament.commands.thenExecute -import moe.nea.firmament.commands.thenLiteral -import moe.nea.firmament.events.CommandEvent -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.events.WorldReadyEvent -import moe.nea.firmament.events.WorldRenderLastEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.ClipboardUtils -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.TimeMark -import moe.nea.firmament.util.render.RenderInWorldContext - -object Waypoints : FirmamentFeature { - override val identifier: String - get() = "waypoints" - - object TConfig : ManagedConfig(identifier) { - val tempWaypointDuration by duration("temp-waypoint-duration", 0.seconds, 1.hours) { 30.seconds } - val showIndex by toggle("show-index") { true } - val skipToNearest by toggle("skip-to-nearest") { false } - // TODO: look ahead size - } - - data class TemporaryWaypoint( - val pos: BlockPos, - val postedAt: TimeMark, - ) - - override val config get() = TConfig - - val temporaryPlayerWaypointList = mutableMapOf<String, TemporaryWaypoint>() - val temporaryPlayerWaypointMatcher = "(?i)x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern() - - val waypoints = mutableListOf<BlockPos>() - var ordered = false - var orderedIndex = 0 - - @Serializable - data class ColeWeightWaypoint( - val x: Int, - val y: Int, - val z: Int, - val r: Int = 0, - val g: Int = 0, - val b: Int = 0, - ) - - @Subscribe - fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) { - if (waypoints.isEmpty()) return - RenderInWorldContext.renderInWorld(event) { - if (!ordered) { - waypoints.withIndex().forEach { - color(0f, 0.3f, 0.7f, 0.5f) - block(it.value) - color(1f, 1f, 1f, 1f) - if (TConfig.showIndex) - withFacingThePlayer(it.value.toCenterPos()) { - text(Text.literal(it.index.toString())) - } - } - } else { - orderedIndex %= waypoints.size - val firstColor = Color.ofRGBA(0, 200, 40, 180) - color(firstColor) - tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f) - waypoints.withIndex().toList() - .wrappingWindow(orderedIndex, 3) - .zip( - listOf( - firstColor, - Color.ofRGBA(180, 200, 40, 150), - Color.ofRGBA(180, 80, 20, 140), - ) - ) - .reversed() - .forEach { (waypoint, col) -> - val (index, pos) = waypoint - color(col) - block(pos) - color(1f, 1f, 1f, 1f) - if (TConfig.showIndex) - withFacingThePlayer(pos.toCenterPos()) { - text(Text.literal(index.toString())) - } - } - } - } - } - - @Subscribe - fun onTick(event: TickEvent) { - if (waypoints.isEmpty() || !ordered) return - orderedIndex %= waypoints.size - val p = MC.player?.pos ?: return - if (TConfig.skipToNearest) { - orderedIndex = - (waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size - } else { - if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) { - orderedIndex = (orderedIndex + 1) % waypoints.size - } - } - } - - @Subscribe - fun onProcessChat(it: ProcessChatEvent) { - val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString) - if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) { - temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint( - BlockPos( - matcher.group(1).toInt(), - matcher.group(2).toInt(), - matcher.group(3).toInt(), - ), - TimeMark.now() - ) - } - } - - @Subscribe - fun onCommand(event: CommandEvent.SubCommand) { - event.subcommand("waypoint") { - thenArgument("pos", BlockPosArgumentType.blockPos()) { pos -> - thenExecute { - val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer()) - waypoints.add(position) - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.command.waypoint.added", - position.x, - position.y, - position.z - ) - ) - } - } - } - event.subcommand("waypoints") { - thenLiteral("clear") { - thenExecute { - waypoints.clear() - source.sendFeedback(Text.translatable("firmament.command.waypoint.clear")) - } - } - thenLiteral("toggleordered") { - thenExecute { - ordered = !ordered - if (ordered) { - val p = MC.player?.pos ?: Vec3d.ZERO - orderedIndex = - waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0 - } - source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered")) - } - } - thenLiteral("skip") { - thenExecute { - if (ordered && waypoints.isNotEmpty()) { - orderedIndex = (orderedIndex + 1) % waypoints.size - source.sendFeedback(Text.translatable("firmament.command.waypoint.skip")) - } else { - source.sendError(Text.translatable("firmament.command.waypoint.skip.error")) - } - } - } - thenLiteral("remove") { - thenArgument("index", IntegerArgumentType.integer(0)) { indexArg -> - thenExecute { - val index = get(indexArg) - if (index in waypoints.indices) { - waypoints.removeAt(index) - source.sendFeedback(Text.stringifiedTranslatable( - "firmament.command.waypoint.remove", - index)) - } else { - source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error")) - } - } - } - } - thenLiteral("import") { - thenExecute { - val contents = ClipboardUtils.getTextContents() - val data = try { - Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents) - } catch (ex: Exception) { - Firmament.logger.error("Could not load waypoints from clipboard", ex) - source.sendError(Text.translatable("firmament.command.waypoint.import.error")) - return@thenExecute - } - waypoints.clear() - data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) } - source.sendFeedback( - Text.stringifiedTranslatable( - "firmament.command.waypoint.import", - data.size - ) - ) - } - } - } - } - - @Subscribe - fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) { - temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } - if (temporaryPlayerWaypointList.isEmpty()) return - RenderInWorldContext.renderInWorld(event) { - color(1f, 1f, 0f, 1f) - temporaryPlayerWaypointList.forEach { (player, waypoint) -> - block(waypoint.pos) - } - color(1f, 1f, 1f, 1f) - temporaryPlayerWaypointList.forEach { (player, waypoint) -> - val skin = - MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } - ?.skinTextures - ?.texture - withFacingThePlayer(waypoint.pos.toCenterPos()) { - waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player)) - if (skin != null) { - matrixStack.translate(0F, -20F, 0F) - // Head front - texture( - skin, 16, 16, - 1 / 8f, 1 / 8f, - 2 / 8f, 2 / 8f, - ) - // Head overlay - texture( - skin, 16, 16, - 5 / 8f, 1 / 8f, - 6 / 8f, 2 / 8f, - ) - } - } - } - } - } - - @Subscribe - fun onWorldReady(event: WorldReadyEvent) { - temporaryPlayerWaypointList.clear() - } -} - -fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> { - val result = ArrayList<E>(windowSize) - if (startIndex + windowSize < size) { - result.addAll(subList(startIndex, startIndex + windowSize)) - } else { - result.addAll(subList(startIndex, size)) - result.addAll(subList(0, minOf(windowSize - (size - startIndex), startIndex))) - } - return result -} - - -fun FabricClientCommandSource.asFakeServer(): ServerCommandSource { - val source = this - return ServerCommandSource( - source.player, - source.position, - source.rotation, - null, - 0, - "FakeServerCommandSource", - Text.literal("FakeServerCommandSource"), - null, - source.player - ) -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/BarComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/BarComponent.kt deleted file mode 100644 index 8ef0753..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/BarComponent.kt +++ /dev/null @@ -1,125 +0,0 @@ - -package moe.nea.firmament.gui - -import com.mojang.blaze3d.systems.RenderSystem -import io.github.notenoughupdates.moulconfig.common.MyResourceLocation -import io.github.notenoughupdates.moulconfig.common.RenderContext -import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext -import me.shedaniel.math.Color -import net.minecraft.client.gui.DrawContext -import net.minecraft.util.Identifier -import moe.nea.firmament.Firmament - -class BarComponent( - val progress: GetSetter<Double>, val total: GetSetter<Double>, - val fillColor: Color, - val emptyColor: Color, -) : GuiComponent() { - override fun getWidth(): Int { - return 80 - } - - override fun getHeight(): Int { - return 8 - } - - data class Texture( - val identifier: Identifier, - val u1: Float, val v1: Float, - val u2: Float, val v2: Float, - ) { - fun draw(context: DrawContext, x: Int, y: Int, width: Int, height: Int, color: Color) { - context.drawTexturedQuad( - identifier, - x, y, x + width, x + height, 0, - u1, u2, v1, v2, - color.red / 255F, - color.green / 255F, - color.blue / 255F, - color.alpha / 255F, - ) - } - } - - companion object { - val resource = Firmament.identifier("textures/gui/bar.png") - val left = Texture(resource, 0 / 64F, 0 / 64F, 4 / 64F, 8 / 64F) - val middle = Texture(resource, 4 / 64F, 0 / 64F, 8 / 64F, 8 / 64F) - val right = Texture(resource, 8 / 64F, 0 / 64F, 12 / 64F, 8 / 64F) - val segmentOverlay = Texture(resource, 12 / 64F, 0 / 64F, 15 / 64F, 8 / 64F) - } - - private fun drawSection( - context: DrawContext, - texture: Texture, - x: Int, - y: Int, - width: Int, - sectionStart: Double, - sectionEnd: Double - ) { - if (sectionEnd < progress.get() && width == 4) { - texture.draw(context, x, y, 4, 8, fillColor) - return - } - if (sectionStart > progress.get() && width == 4) { - texture.draw(context, x, y, 4, 8, emptyColor) - return - } - val increasePerPixel = (sectionEnd - sectionStart) / width - var valueAtPixel = sectionStart - for (i in (0 until width)) { - val newTex = - Texture(texture.identifier, texture.u1 + i / 64F, texture.v1, texture.u1 + (i + 1) / 64F, texture.v2) - newTex.draw( - context, x + i, y, 1, 8, - if (valueAtPixel < progress.get()) fillColor else emptyColor - ) - valueAtPixel += increasePerPixel - } - } - - override fun render(context: GuiImmediateContext) { - val renderContext = (context.renderContext as ModernRenderContext).drawContext - var i = 0 - val x = 0 - val y = 0 - while (i < context.width - 4) { - drawSection( - renderContext, - if (i == 0) left else middle, - x + i, y, - (context.width - (i + 4)).coerceAtMost(4), - i * total.get() / context.width, (i + 4) * total.get() / context.width - ) - i += 4 - } - drawSection( - renderContext, - right, - x + context.width - 4, - y, - 4, - (context.width - 4) * total.get() / context.width, - total.get() - ) - RenderSystem.setShaderColor(1F, 1F, 1F, 1F) - - } - -} - -fun Identifier.toMoulConfig(): MyResourceLocation { - return MyResourceLocation(this.namespace, this.path) -} - -fun RenderContext.color(color: Color) { - color(color.red, color.green, color.blue, color.alpha) -} - -fun RenderContext.color(red: Int, green: Int, blue: Int, alpha: Int) { - color(red / 255f, green / 255f, blue / 255f, alpha / 255f) -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/FirmButtonComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/FirmButtonComponent.kt deleted file mode 100644 index 82e5b05..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/FirmButtonComponent.kt +++ /dev/null @@ -1,81 +0,0 @@ - -package moe.nea.firmament.gui - -import io.github.notenoughupdates.moulconfig.common.MyResourceLocation -import io.github.notenoughupdates.moulconfig.deps.libninepatch.NinePatch -import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext -import io.github.notenoughupdates.moulconfig.gui.MouseEvent -import io.github.notenoughupdates.moulconfig.gui.component.PanelComponent -import io.github.notenoughupdates.moulconfig.observer.GetSetter - - -open class FirmButtonComponent( - child: GuiComponent, - val isEnabled: GetSetter<Boolean> = GetSetter.constant(true), - val noBackground: Boolean = false, - val action: Runnable, -) : PanelComponent(child, if (noBackground) 0 else 2, DefaultBackgroundRenderer.TRANSPARENT) { - - /* TODO: make use of vanillas built in nine slicer */ - val hoveredBg = - NinePatch.builder(MyResourceLocation("minecraft", "textures/gui/sprites/widget/button_highlighted.png")) - .cornerSize(5) - .cornerUv(5 / 200F, 5 / 20F) - .mode(NinePatch.Mode.STRETCHING) - .build() - val unhoveredBg = NinePatch.builder(MyResourceLocation("minecraft", "textures/gui/sprites/widget/button.png")) - .cornerSize(5) - .cornerUv(5 / 200F, 5 / 20F) - .mode(NinePatch.Mode.STRETCHING) - .build() - val disabledBg = - NinePatch.builder(MyResourceLocation("minecraft", "textures/gui/sprites/widget/button_disabled.png")) - .cornerSize(5) - .cornerUv(5 / 200F, 5 / 20F) - .mode(NinePatch.Mode.STRETCHING) - .build() - val activeBg = NinePatch.builder(MyResourceLocation("firmament", "textures/gui/sprites/widget/button_active.png")) - .cornerSize(5) - .cornerUv(5 / 200F, 5 / 20F) - .mode(NinePatch.Mode.STRETCHING) - .build() - var isClicking = false - override fun mouseEvent(mouseEvent: MouseEvent, context: GuiImmediateContext): Boolean { - if (!isEnabled.get()) return false - if (isClicking) { - if (mouseEvent is MouseEvent.Click && !mouseEvent.mouseState && mouseEvent.mouseButton == 0) { - isClicking = false - if (context.isHovered) { - action.run() - } - return true - } - } - if (!context.isHovered) return false - if (mouseEvent !is MouseEvent.Click) return false - if (mouseEvent.mouseState && mouseEvent.mouseButton == 0) { - requestFocus() - isClicking = true - return true - } - return false - } - - open fun getBackground(context: GuiImmediateContext): NinePatch<MyResourceLocation> = - if (!isEnabled.get()) disabledBg - else if (context.isHovered || isClicking) hoveredBg - else unhoveredBg - - override fun render(context: GuiImmediateContext) { - context.renderContext.pushMatrix() - if (!noBackground) - context.renderContext.drawNinePatch( - getBackground(context), - 0f, 0f, context.width, context.height - ) - context.renderContext.translate(insets.toFloat(), insets.toFloat(), 0f) - element.render(getChildContext(context)) - context.renderContext.popMatrix() - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/FirmHoverComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/FirmHoverComponent.kt deleted file mode 100644 index b1792ce..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/FirmHoverComponent.kt +++ /dev/null @@ -1,59 +0,0 @@ -package moe.nea.firmament.gui - -import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext -import io.github.notenoughupdates.moulconfig.gui.KeyboardEvent -import io.github.notenoughupdates.moulconfig.gui.MouseEvent -import java.util.function.BiFunction -import java.util.function.Supplier -import kotlin.time.Duration -import moe.nea.firmament.util.TimeMark - -class FirmHoverComponent( - val child: GuiComponent, - val hoverLines: Supplier<List<String>>, - val hoverDelay: Duration, -) : GuiComponent() { - override fun getWidth(): Int { - return child.width - } - - override fun getHeight(): Int { - return child.height - } - - override fun <T : Any?> foldChildren( - initial: T, - visitor: BiFunction<GuiComponent, T, T> - ): T { - return visitor.apply(child, initial) - } - - override fun render(context: GuiImmediateContext) { - if (context.isHovered && (permaHover || lastMouseMove.passedTime() > hoverDelay)) { - context.renderContext.scheduleDrawTooltip(hoverLines.get()) - permaHover = true - } else { - permaHover = false - } - if (!context.isHovered) { - lastMouseMove = TimeMark.now() - } - child.render(context) - - } - - var permaHover = false - var lastMouseMove = TimeMark.farPast() - - override fun mouseEvent(mouseEvent: MouseEvent, context: GuiImmediateContext): Boolean { - if (mouseEvent is MouseEvent.Move) { - lastMouseMove = TimeMark.now() - } - return child.mouseEvent(mouseEvent, context) - } - - override fun keyboardEvent(event: KeyboardEvent, context: GuiImmediateContext): Boolean { - return child.keyboardEvent(event, context) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/FixedComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/FixedComponent.kt deleted file mode 100644 index ae1da2d..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/FixedComponent.kt +++ /dev/null @@ -1,38 +0,0 @@ - -package moe.nea.firmament.gui - -import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext -import io.github.notenoughupdates.moulconfig.gui.KeyboardEvent -import io.github.notenoughupdates.moulconfig.gui.MouseEvent -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import java.util.function.BiFunction - -class FixedComponent( - val fixedWidth: GetSetter<Int>?, - val fixedHeight: GetSetter<Int>?, - val component: GuiComponent, -) : GuiComponent() { - override fun getWidth(): Int = fixedWidth?.get() ?: component.width - - override fun getHeight(): Int = fixedHeight?.get() ?: component.height - - override fun <T : Any?> foldChildren(initial: T, visitor: BiFunction<GuiComponent, T, T>): T { - return visitor.apply(component, initial) - } - - fun fixContext(context: GuiImmediateContext): GuiImmediateContext = - context.translated(0, 0, width, height) - - override fun render(context: GuiImmediateContext) { - component.render(fixContext(context)) - } - - override fun mouseEvent(mouseEvent: MouseEvent, context: GuiImmediateContext): Boolean { - return component.mouseEvent(mouseEvent, fixContext(context)) - } - - override fun keyboardEvent(event: KeyboardEvent, context: GuiImmediateContext): Boolean { - return component.keyboardEvent(event, fixContext(context)) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/ImageComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/ImageComponent.kt deleted file mode 100644 index bba7dee..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/ImageComponent.kt +++ /dev/null @@ -1,33 +0,0 @@ -package moe.nea.firmament.gui - -import io.github.notenoughupdates.moulconfig.common.MyResourceLocation -import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext -import java.util.function.Supplier - -class ImageComponent( - private val width: Int, - private val height: Int, - val resourceLocation: Supplier<MyResourceLocation>, - val u1: Float, - val u2: Float, - val v1: Float, - val v2: Float, -) : GuiComponent() { - override fun getWidth(): Int { - return width - } - - override fun getHeight(): Int { - return height - } - - override fun render(context: GuiImmediateContext) { - context.renderContext.bindTexture(resourceLocation.get()) - context.renderContext.drawTexturedRect( - 0f, 0f, - context.width.toFloat(), context.height.toFloat(), - u1, v1, u2, v2 - ) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/TickComponent.kt b/src/main/kotlin/moe/nea/firmament/gui/TickComponent.kt deleted file mode 100644 index d1879b1..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/TickComponent.kt +++ /dev/null @@ -1,18 +0,0 @@ -package moe.nea.firmament.gui - -import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext - -class TickComponent(val onTick: Runnable) : GuiComponent() { - override fun getWidth(): Int { - return 0 - } - - override fun getHeight(): Int { - return 0 - } - - override fun render(context: GuiImmediateContext) { - onTick.run() - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/AllConfigsGui.kt b/src/main/kotlin/moe/nea/firmament/gui/config/AllConfigsGui.kt deleted file mode 100644 index 4f7731c..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/AllConfigsGui.kt +++ /dev/null @@ -1,46 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.observer.ObservableList -import io.github.notenoughupdates.moulconfig.xml.Bind -import net.minecraft.client.gui.screen.Screen -import net.minecraft.text.Text -import moe.nea.firmament.features.FeatureManager -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.MoulConfigUtils -import moe.nea.firmament.util.ScreenUtil.setScreenLater - -object AllConfigsGui { - - val allConfigs - get() = listOf( - RepoManager.Config - ) + FeatureManager.allFeatures.mapNotNull { it.config } - - fun <T> List<T>.toObservableList(): ObservableList<T> = ObservableList(this) - - class MainMapping(val allConfigs: List<ManagedConfig>) { - @get:Bind("configs") - val configs = allConfigs.map { EntryMapping(it) }.toObservableList() - - class EntryMapping(val config: ManagedConfig) { - @Bind - fun name() = Text.translatable("firmament.config.${config.name}").string - - @Bind - fun openEditor() { - config.showConfigEditor(MC.screen) - } - } - } - - fun makeScreen(parent: Screen? = null): Screen { - return MoulConfigUtils.loadScreen("config/main", MainMapping(allConfigs), parent) - } - - fun showAllGuis() { - setScreenLater(makeScreen()) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/BooleanHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/BooleanHandler.kt deleted file mode 100644 index 8592777..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/BooleanHandler.kt +++ /dev/null @@ -1,37 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.gui.component.CenterComponent -import io.github.notenoughupdates.moulconfig.gui.component.SwitchComponent -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.boolean -import kotlinx.serialization.json.jsonPrimitive - -class BooleanHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<Boolean> { - override fun toJson(element: Boolean): JsonElement? { - return JsonPrimitive(element) - } - - override fun fromJson(element: JsonElement): Boolean { - return element.jsonPrimitive.boolean - } - - override fun emitGuiElements(opt: ManagedOption<Boolean>, guiAppender: GuiAppender) { - guiAppender.appendLabeledRow( - opt.labelText, - CenterComponent(SwitchComponent(object : GetSetter<Boolean> { - override fun get(): Boolean { - return opt.get() - } - - override fun set(newValue: Boolean) { - opt.set(newValue) - config.save() - } - }, 200) - )) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ClickHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ClickHandler.kt deleted file mode 100644 index fa1c621..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/ClickHandler.kt +++ /dev/null @@ -1,24 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.gui.component.TextComponent -import kotlinx.serialization.json.JsonElement -import moe.nea.firmament.gui.FirmButtonComponent - -class ClickHandler(val config: ManagedConfig, val runnable: () -> Unit) : ManagedConfig.OptionHandler<Unit> { - override fun toJson(element: Unit): JsonElement? { - return null - } - - override fun fromJson(element: JsonElement) {} - - override fun emitGuiElements(opt: ManagedOption<Unit>, guiAppender: GuiAppender) { - guiAppender.appendLabeledRow( - opt.labelText, - FirmButtonComponent( - TextComponent(opt.labelText.string), - action = runnable), - ) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/DurationHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/DurationHandler.kt deleted file mode 100644 index 8d485b1..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/DurationHandler.kt +++ /dev/null @@ -1,58 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.common.IMinecraft -import io.github.notenoughupdates.moulconfig.gui.component.RowComponent -import io.github.notenoughupdates.moulconfig.gui.component.SliderComponent -import io.github.notenoughupdates.moulconfig.gui.component.TextComponent -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.jsonPrimitive -import kotlinx.serialization.json.long -import kotlin.time.Duration -import kotlin.time.DurationUnit -import kotlin.time.toDuration -import net.minecraft.text.Text -import moe.nea.firmament.util.FirmFormatters - -class DurationHandler(val config: ManagedConfig, val min: Duration, val max: Duration) : - ManagedConfig.OptionHandler<Duration> { - override fun toJson(element: Duration): JsonElement? { - return JsonPrimitive(element.inWholeMilliseconds) - } - - override fun fromJson(element: JsonElement): Duration { - return element.jsonPrimitive.long.toDuration(DurationUnit.MILLISECONDS) - } - - override fun emitGuiElements(opt: ManagedOption<Duration>, guiAppender: GuiAppender) { - guiAppender.appendLabeledRow( - opt.labelText, - RowComponent( - TextComponent(IMinecraft.instance.defaultFontRenderer, - { FirmFormatters.formatTimespan(opt.value) }, - 40, - TextComponent.TextAlignment.CENTER, - true, - false), - SliderComponent( - object : GetSetter<Float> { - override fun get(): Float { - return opt.value.toDouble(DurationUnit.SECONDS).toFloat() - } - - override fun set(newValue: Float) { - opt.value = newValue.toDouble().toDuration(DurationUnit.SECONDS) - } - }, - min.toDouble(DurationUnit.SECONDS).toFloat(), - max.toDouble(DurationUnit.SECONDS).toFloat(), - 0.1F, - 130 - ) - )) - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt b/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt deleted file mode 100644 index 329319d..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/GuiAppender.kt +++ /dev/null @@ -1,40 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.component.RowComponent -import io.github.notenoughupdates.moulconfig.gui.component.TextComponent -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import net.minecraft.client.gui.screen.Screen -import net.minecraft.text.Text -import moe.nea.firmament.gui.FixedComponent - -class GuiAppender(val width: Int, val screenAccessor: () -> Screen) { - val panel = mutableListOf<GuiComponent>() - internal val reloadables = mutableListOf<(() -> Unit)>() - - fun onReload(reloadable: () -> Unit) { - reloadables.add(reloadable) - } - - fun appendLabeledRow(label: Text, right: GuiComponent) { - appendSplitRow( - TextComponent(label.string), - right - ) - } - - fun appendSplitRow(left: GuiComponent, right: GuiComponent) { - // TODO: make this more dynamic - // i could just make a component that allows for using half the available size - appendFullRow(RowComponent( - FixedComponent(GetSetter.constant(width / 2), null, left), - FixedComponent(GetSetter.constant(width / 2), null, right), - )) - } - - fun appendFullRow(widget: GuiComponent) { - panel.add(widget) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/HudMetaHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/HudMetaHandler.kt deleted file mode 100644 index 35c9d51..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/HudMetaHandler.kt +++ /dev/null @@ -1,39 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.gui.component.TextComponent -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.decodeFromJsonElement -import kotlinx.serialization.json.encodeToJsonElement -import net.minecraft.text.MutableText -import net.minecraft.text.Text -import moe.nea.firmament.gui.FirmButtonComponent -import moe.nea.firmament.jarvis.JarvisIntegration -import moe.nea.firmament.util.MC - -class HudMetaHandler(val config: ManagedConfig, val label: MutableText, val width: Int, val height: Int) : - ManagedConfig.OptionHandler<HudMeta> { - override fun toJson(element: HudMeta): JsonElement? { - return Json.encodeToJsonElement(element.position) - } - - override fun fromJson(element: JsonElement): HudMeta { - return HudMeta(Json.decodeFromJsonElement(element), label, width, height) - } - - override fun emitGuiElements(opt: ManagedOption<HudMeta>, guiAppender: GuiAppender) { - guiAppender.appendLabeledRow( - opt.labelText, - FirmButtonComponent( - TextComponent( - Text.stringifiedTranslatable("firmament.hud.edit", label).string), - ) { - MC.screen = JarvisIntegration.jarvis.getHudEditor( - guiAppender.screenAccessor.invoke(), - listOf(opt.value) - ) - }) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/IntegerHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/IntegerHandler.kt deleted file mode 100644 index 31ce90f..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/IntegerHandler.kt +++ /dev/null @@ -1,54 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.common.IMinecraft -import io.github.notenoughupdates.moulconfig.gui.component.RowComponent -import io.github.notenoughupdates.moulconfig.gui.component.SliderComponent -import io.github.notenoughupdates.moulconfig.gui.component.TextComponent -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.int -import kotlinx.serialization.json.jsonPrimitive -import moe.nea.firmament.util.FirmFormatters - -class IntegerHandler(val config: ManagedConfig, val min: Int, val max: Int) : ManagedConfig.OptionHandler<Int> { - override fun toJson(element: Int): JsonElement? { - return JsonPrimitive(element) - } - - override fun fromJson(element: JsonElement): Int { - return element.jsonPrimitive.int - } - - override fun emitGuiElements(opt: ManagedOption<Int>, guiAppender: GuiAppender) { - guiAppender.appendLabeledRow( - opt.labelText, - RowComponent( - TextComponent(IMinecraft.instance.defaultFontRenderer, - { FirmFormatters.formatCommas(opt.value, 0) }, - 40, - TextComponent.TextAlignment.CENTER, - true, - false), - SliderComponent( - object : GetSetter<Float> { - override fun get(): Float { - return opt.value.toFloat() - } - - override fun set(newValue: Float) { - opt.value = newValue.toInt() - } - }, - min.toFloat(), - max.toFloat(), - 0.1F, - 130 - ) - )) - - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/JAnyHud.kt b/src/main/kotlin/moe/nea/firmament/gui/config/JAnyHud.kt deleted file mode 100644 index 35c4eb2..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/JAnyHud.kt +++ /dev/null @@ -1,48 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import moe.nea.jarvis.api.JarvisHud -import moe.nea.jarvis.api.JarvisScalable -import kotlinx.serialization.Serializable -import net.minecraft.text.Text - -@Serializable -data class HudPosition( - var x: Double, - var y: Double, - var scale: Float, -) - - -data class HudMeta( - val position: HudPosition, - private val label: Text, - private val width: Int, - private val height: Int, -) : JarvisScalable, JarvisHud { - override fun getX(): Double = position.x - - override fun setX(newX: Double) { - position.x = newX - } - - override fun getY(): Double = position.y - - override fun setY(newY: Double) { - position.y = newY - } - - override fun getLabel(): Text = label - - override fun getWidth(): Int = width - - override fun getHeight(): Int = height - - override fun getScale(): Float = position.scale - - override fun setScale(newScale: Float) { - position.scale = newScale - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/KeyBindingHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/KeyBindingHandler.kt deleted file mode 100644 index c389cc9..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/KeyBindingHandler.kt +++ /dev/null @@ -1,149 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.common.IMinecraft -import io.github.notenoughupdates.moulconfig.common.MyResourceLocation -import io.github.notenoughupdates.moulconfig.deps.libninepatch.NinePatch -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext -import io.github.notenoughupdates.moulconfig.gui.KeyboardEvent -import io.github.notenoughupdates.moulconfig.gui.component.TextComponent -import org.lwjgl.glfw.GLFW -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.decodeFromJsonElement -import kotlinx.serialization.json.encodeToJsonElement -import net.minecraft.text.Text -import net.minecraft.util.Formatting -import moe.nea.firmament.gui.FirmButtonComponent -import moe.nea.firmament.keybindings.FirmamentKeyBindings -import moe.nea.firmament.keybindings.SavedKeyBinding - -class KeyBindingHandler(val name: String, val managedConfig: ManagedConfig) : - ManagedConfig.OptionHandler<SavedKeyBinding> { - - override fun initOption(opt: ManagedOption<SavedKeyBinding>) { - FirmamentKeyBindings.registerKeyBinding(name, opt) - } - - override fun toJson(element: SavedKeyBinding): JsonElement? { - return Json.encodeToJsonElement(element) - } - - override fun fromJson(element: JsonElement): SavedKeyBinding { - return Json.decodeFromJsonElement(element) - } - - override fun emitGuiElements(opt: ManagedOption<SavedKeyBinding>, guiAppender: GuiAppender) { - var editing = false - var lastPressed = 0 - var lastPressedNonModifier = 0 - var label: String = "" - var button: FirmButtonComponent? = null - fun updateLabel() { - var stroke = opt.value.format() - if (editing) { - stroke = Text.literal("") - val (shift, alt, ctrl) = SavedKeyBinding.getMods(SavedKeyBinding.getModInt()) - if (shift) { - stroke.append("SHIFT + ") - } - if (alt) { - stroke.append("ALT + ") - } - if (ctrl) { - stroke.append("CTRL + ") - } - stroke.append("???") - stroke.styled { it.withColor(Formatting.YELLOW) } - } - label = (stroke).string - managedConfig.save() - } - button = object : FirmButtonComponent( - TextComponent( - IMinecraft.instance.defaultFontRenderer, - { label }, - 130, - TextComponent.TextAlignment.LEFT, - false, - false - ), action = { - if (editing) { - button!!.blur() - } else { - editing = true - button!!.requestFocus() - updateLabel() - } - }) { - override fun keyboardEvent(event: KeyboardEvent, context: GuiImmediateContext): Boolean { - if (event is KeyboardEvent.KeyPressed) { - return if (event.pressed) onKeyPressed(event.keycode, SavedKeyBinding.getModInt()) - else onKeyReleased(event.keycode, SavedKeyBinding.getModInt()) - } - return super.keyboardEvent(event, context) - } - - override fun getBackground(context: GuiImmediateContext): NinePatch<MyResourceLocation> { - if (editing) return activeBg - return super.getBackground(context) - } - - fun onKeyPressed(ch: Int, modifiers: Int): Boolean { - if (!editing) { - return false - } - if (ch == GLFW.GLFW_KEY_ESCAPE) { - lastPressedNonModifier = 0 - editing = false - lastPressed = 0 - opt.value = SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN) - updateLabel() - blur() - return true - } - if (ch == GLFW.GLFW_KEY_LEFT_SHIFT || ch == GLFW.GLFW_KEY_RIGHT_SHIFT - || ch == GLFW.GLFW_KEY_LEFT_ALT || ch == GLFW.GLFW_KEY_RIGHT_ALT - || ch == GLFW.GLFW_KEY_LEFT_CONTROL || ch == GLFW.GLFW_KEY_RIGHT_CONTROL - ) { - lastPressed = ch - } else { - opt.value = SavedKeyBinding( - ch, modifiers - ) - editing = false - blur() - lastPressed = 0 - lastPressedNonModifier = 0 - } - updateLabel() - return true - } - - override fun onLostFocus() { - lastPressedNonModifier = 0 - editing = false - lastPressed = 0 - updateLabel() - } - - fun onKeyReleased(ch: Int, modifiers: Int): Boolean { - if (!editing) - return false - if (lastPressedNonModifier == ch || (lastPressedNonModifier == 0 && ch == lastPressed)) { - opt.value = SavedKeyBinding(ch, modifiers) - editing = false - blur() - lastPressed = 0 - lastPressedNonModifier = 0 - } - updateLabel() - return true - } - } - updateLabel() - guiAppender.appendLabeledRow(opt.labelText, button) - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt deleted file mode 100644 index aa6e3c8..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfig.kt +++ /dev/null @@ -1,181 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.gui.CloseEventListener -import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper -import io.github.notenoughupdates.moulconfig.gui.GuiContext -import io.github.notenoughupdates.moulconfig.gui.component.CenterComponent -import io.github.notenoughupdates.moulconfig.gui.component.ColumnComponent -import io.github.notenoughupdates.moulconfig.gui.component.PanelComponent -import io.github.notenoughupdates.moulconfig.gui.component.RowComponent -import io.github.notenoughupdates.moulconfig.gui.component.ScrollPanelComponent -import io.github.notenoughupdates.moulconfig.gui.component.TextComponent -import moe.nea.jarvis.api.Point -import org.lwjgl.glfw.GLFW -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonObject -import kotlin.io.path.createDirectories -import kotlin.io.path.readText -import kotlin.io.path.writeText -import kotlin.time.Duration -import net.minecraft.client.gui.screen.Screen -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.gui.FirmButtonComponent -import moe.nea.firmament.keybindings.SavedKeyBinding -import moe.nea.firmament.util.ScreenUtil.setScreenLater - -abstract class ManagedConfig(override val name: String) : ManagedConfigElement() { - - interface OptionHandler<T : Any> { - fun initOption(opt: ManagedOption<T>) {} - fun toJson(element: T): JsonElement? - fun fromJson(element: JsonElement): T - fun emitGuiElements(opt: ManagedOption<T>, guiAppender: GuiAppender) - } - - val file = Firmament.CONFIG_DIR.resolve("$name.json") - val data: JsonObject by lazy { - try { - Firmament.json.decodeFromString( - file.readText() - ) - } catch (e: Exception) { - Firmament.logger.info("Could not read config $name. Loading empty config.") - JsonObject(mutableMapOf()) - } - } - - fun save() { - val data = JsonObject(allOptions.mapNotNull { (key, value) -> - value.toJson()?.let { - key to it - } - }.toMap()) - file.parent.createDirectories() - file.writeText(Firmament.json.encodeToString(data)) - } - - - val allOptions = mutableMapOf<String, ManagedOption<*>>() - val sortedOptions = mutableListOf<ManagedOption<*>>() - - private var latestGuiAppender: GuiAppender? = null - - protected fun <T : Any> option( - propertyName: String, - default: () -> T, - handler: OptionHandler<T> - ): ManagedOption<T> { - if (propertyName in allOptions) error("Cannot register the same name twice") - return ManagedOption(this, propertyName, default, handler).also { - it.handler.initOption(it) - it.load(data) - allOptions[propertyName] = it - sortedOptions.add(it) - } - } - - protected fun toggle(propertyName: String, default: () -> Boolean): ManagedOption<Boolean> { - return option(propertyName, default, BooleanHandler(this)) - } - - protected fun duration( - propertyName: String, - min: Duration, - max: Duration, - default: () -> Duration, - ): ManagedOption<Duration> { - return option(propertyName, default, DurationHandler(this, min, max)) - } - - - protected fun position( - propertyName: String, - width: Int, - height: Int, - default: () -> Point, - ): ManagedOption<HudMeta> { - val label = Text.translatable("firmament.config.${name}.${propertyName}") - return option(propertyName, { - val p = default() - HudMeta(HudPosition(p.x, p.y, 1F), label, width, height) - }, HudMetaHandler(this, label, width, height)) - } - - protected fun keyBinding( - propertyName: String, - default: () -> Int, - ): ManagedOption<SavedKeyBinding> = keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(default()) } - - protected fun keyBindingWithOutDefaultModifiers( - propertyName: String, - default: () -> SavedKeyBinding, - ): ManagedOption<SavedKeyBinding> { - return option(propertyName, default, KeyBindingHandler("firmament.config.${name}.${propertyName}", this)) - } - - protected fun keyBindingWithDefaultUnbound( - propertyName: String, - ): ManagedOption<SavedKeyBinding> { - return keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN) } - } - - protected fun integer( - propertyName: String, - min: Int, - max: Int, - default: () -> Int, - ): ManagedOption<Int> { - return option(propertyName, default, IntegerHandler(this, min, max)) - } - - protected fun button(propertyName: String, runnable: () -> Unit): ManagedOption<Unit> { - return option(propertyName, { }, ClickHandler(this, runnable)) - } - - protected fun string(propertyName: String, default: () -> String): ManagedOption<String> { - return option(propertyName, default, StringHandler(this)) - } - - - fun reloadGui() { - latestGuiAppender?.reloadables?.forEach { it() } - } - - val labelText = Text.translatable("firmament.config.${name}") - - fun getConfigEditor(parent: Screen? = null): Screen { - var screen: Screen? = null - val guiapp = GuiAppender(400) { requireNotNull(screen) { "Screen Accessor called too early" } } - latestGuiAppender = guiapp - guiapp.appendFullRow(RowComponent( - FirmButtonComponent(TextComponent("←")) { - if (parent != null) { - save() - setScreenLater(parent) - } else { - AllConfigsGui.showAllGuis() - } - } - )) - sortedOptions.forEach { it.appendToGui(guiapp) } - guiapp.reloadables.forEach { it() } - val component = CenterComponent(PanelComponent(ScrollPanelComponent(400, 300, ColumnComponent(guiapp.panel)), 10, PanelComponent.DefaultBackgroundRenderer.VANILLA)) - screen = object : GuiComponentWrapper(GuiContext(component)) { - override fun close() { - if (context.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) { - client!!.setScreen(parent) - } - } - } - return screen - } - - fun showConfigEditor(parent: Screen? = null) { - setScreenLater(getConfigEditor(parent)) - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfigElement.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfigElement.kt deleted file mode 100644 index 28cd6b8..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedConfigElement.kt +++ /dev/null @@ -1,8 +0,0 @@ - - -package moe.nea.firmament.gui.config - -abstract class ManagedConfigElement { - abstract val name: String - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedOption.kt b/src/main/kotlin/moe/nea/firmament/gui/config/ManagedOption.kt deleted file mode 100644 index b7264e8..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/ManagedOption.kt +++ /dev/null @@ -1,62 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonObject -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty -import net.minecraft.text.Text -import moe.nea.firmament.Firmament - -class ManagedOption<T : Any>( - val element: ManagedConfigElement, - val propertyName: String, - val default: () -> T, - val handler: ManagedConfig.OptionHandler<T> -) : ReadWriteProperty<Any?, T>, GetSetter<T> { - override fun set(newValue: T) { - this.value = newValue - } - - override fun get(): T { - return this.value - } - - val rawLabelText = "firmament.config.${element.name}.${propertyName}" - val labelText = Text.translatable(rawLabelText) - - lateinit var value: T - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { - this.value = value - } - - override fun getValue(thisRef: Any?, property: KProperty<*>): T { - return value - } - - fun load(root: JsonElement) { - if (root is JsonObject && root.containsKey(propertyName)) { - try { - value = handler.fromJson(root[propertyName]!!) - return - } catch (e: Exception) { - Firmament.logger.error( - "Exception during loading of config file ${element.name}. This will reset this config.", - e - ) - } - } - value = default() - } - - fun toJson(): JsonElement? { - return handler.toJson(value) - } - - fun appendToGui(guiapp: GuiAppender) { - handler.emitGuiElements(this, guiapp) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/config/StringHandler.kt b/src/main/kotlin/moe/nea/firmament/gui/config/StringHandler.kt deleted file mode 100644 index a326abb..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/config/StringHandler.kt +++ /dev/null @@ -1,36 +0,0 @@ - - -package moe.nea.firmament.gui.config - -import io.github.notenoughupdates.moulconfig.gui.component.TextFieldComponent -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.jsonPrimitive -import net.minecraft.text.Text - -class StringHandler(val config: ManagedConfig) : ManagedConfig.OptionHandler<String> { - override fun toJson(element: String): JsonElement? { - return JsonPrimitive(element) - } - - override fun fromJson(element: JsonElement): String { - return element.jsonPrimitive.content - } - - override fun emitGuiElements(opt: ManagedOption<String>, guiAppender: GuiAppender) { - guiAppender.appendLabeledRow( - opt.labelText, - TextFieldComponent( - object : GetSetter<String> by opt { - override fun set(newValue: String) { - opt.set(newValue) - config.save() - } - }, - 130, - suggestion = Text.translatableWithFallback(opt.rawLabelText + ".hint", "").string - ), - ) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityModifier.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityModifier.kt deleted file mode 100644 index 9623070..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityModifier.kt +++ /dev/null @@ -1,9 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import net.minecraft.entity.LivingEntity - -fun interface EntityModifier { - fun apply(entity: LivingEntity, info: JsonObject): LivingEntity -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt deleted file mode 100644 index 8c7428d..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt +++ /dev/null @@ -1,197 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonObject -import org.apache.logging.log4j.LogManager -import org.joml.Quaternionf -import org.joml.Vector3f -import kotlin.math.atan -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.screen.ingame.InventoryScreen -import net.minecraft.entity.Entity -import net.minecraft.entity.EntityType -import net.minecraft.entity.LivingEntity -import net.minecraft.util.Identifier -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.assertNotNullOr -import moe.nea.firmament.util.iterate -import moe.nea.firmament.util.openFirmamentResource -import moe.nea.firmament.util.render.enableScissorWithTranslation - -object EntityRenderer { - val fakeWorld = FakeWorld() - private fun <T : Entity> t(entityType: EntityType<T>): () -> T { - return { entityType.create(fakeWorld)!! } - } - - val entityIds: Map<String, () -> LivingEntity> = mapOf( - "Zombie" to t(EntityType.ZOMBIE), - "Chicken" to t(EntityType.CHICKEN), - "Slime" to t(EntityType.SLIME), - "Wolf" to t(EntityType.WOLF), - "Skeleton" to t(EntityType.SKELETON), - "Creeper" to t(EntityType.CREEPER), - "Ocelot" to t(EntityType.OCELOT), - "Blaze" to t(EntityType.BLAZE), - "Rabbit" to t(EntityType.RABBIT), - "Sheep" to t(EntityType.SHEEP), - "Horse" to t(EntityType.HORSE), - "Eisengolem" to t(EntityType.IRON_GOLEM), - "Silverfish" to t(EntityType.SILVERFISH), - "Witch" to t(EntityType.WITCH), - "Endermite" to t(EntityType.ENDERMITE), - "Snowman" to t(EntityType.SNOW_GOLEM), - "Villager" to t(EntityType.VILLAGER), - "Guardian" to t(EntityType.GUARDIAN), - "ArmorStand" to t(EntityType.ARMOR_STAND), - "Squid" to t(EntityType.SQUID), - "Bat" to t(EntityType.BAT), - "Spider" to t(EntityType.SPIDER), - "CaveSpider" to t(EntityType.CAVE_SPIDER), - "Pigman" to t(EntityType.ZOMBIFIED_PIGLIN), - "Ghast" to t(EntityType.GHAST), - "MagmaCube" to t(EntityType.MAGMA_CUBE), - "Wither" to t(EntityType.WITHER), - "Enderman" to t(EntityType.ENDERMAN), - "Mooshroom" to t(EntityType.MOOSHROOM), - "WitherSkeleton" to t(EntityType.WITHER_SKELETON), - "Cow" to t(EntityType.COW), - "Dragon" to t(EntityType.ENDER_DRAGON), - "Player" to { makeGuiPlayer(fakeWorld) }, - "Pig" to t(EntityType.PIG), - "Giant" to t(EntityType.GIANT), - ) - val entityModifiers: Map<String, EntityModifier> = mapOf( - "playerdata" to ModifyPlayerSkin, - "equipment" to ModifyEquipment, - "riding" to ModifyRiding, - "charged" to ModifyCharged, - "witherdata" to ModifyWither, - "invisible" to ModifyInvisible, - "age" to ModifyAge, - "horse" to ModifyHorse, - "name" to ModifyName, - ) - - val logger = LogManager.getLogger("Firmament.Entity") - fun applyModifiers(entityId: String, modifiers: List<JsonObject>): LivingEntity? { - val entityType = assertNotNullOr(entityIds[entityId]) { - logger.error("Could not create entity with id $entityId") - return null - } - var entity = entityType() - for (modifierJson in modifiers) { - val modifier = assertNotNullOr(modifierJson["type"]?.asString?.let(entityModifiers::get)) { - logger.error("Unknown modifier $modifierJson") - return null - } - entity = modifier.apply(entity, modifierJson) - } - return entity - } - - fun constructEntity(info: JsonObject): LivingEntity? { - val modifiers = (info["modifiers"] as JsonArray?)?.map { it.asJsonObject } ?: emptyList() - val entityType = assertNotNullOr(info["entity"]?.asString) { - logger.error("Missing entity type on entity object") - return null - } - return applyModifiers(entityType, modifiers) - } - - private val gson = Gson() - fun constructEntity(location: Identifier): LivingEntity? { - return constructEntity( - gson.fromJson( - location.openFirmamentResource().bufferedReader(), JsonObject::class.java - ) - ) - } - - fun renderEntity( - entity: LivingEntity, - renderContext: DrawContext, - posX: Int, - posY: Int, - mouseX: Float, - mouseY: Float - ) { - var bottomOffset = 0.0F - var currentEntity = entity - val maxSize = entity.iterate { it.firstPassenger as? LivingEntity } - .map { it.height } - .sum() - while (true) { - currentEntity.age = MC.player?.age ?: 0 - drawEntity( - renderContext, - posX, - posY, - posX + 50, - posY + 80, - minOf(2F / maxSize, 1F) * 30, - -bottomOffset, - mouseX, - mouseY, - currentEntity - ) - val next = currentEntity.firstPassenger as? LivingEntity ?: break - bottomOffset += currentEntity.getPassengerRidingPos(next).y.toFloat() * 0.75F - currentEntity = next - } - } - - - fun drawEntity( - context: DrawContext, - x1: Int, - y1: Int, - x2: Int, - y2: Int, - size: Float, - bottomOffset: Float, - mouseX: Float, - mouseY: Float, - entity: LivingEntity - ) { - context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat()) - val centerX = (x1 + x2) / 2f - val centerY = (y1 + y2) / 2f - val targetYaw = atan(((centerX - mouseX) / 40.0f).toDouble()).toFloat() - val targetPitch = atan(((centerY - mouseY) / 40.0f).toDouble()).toFloat() - val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat()) - val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180)) - rotateToFaceTheFront.mul(rotateToFaceTheCamera) - val oldBodyYaw = entity.bodyYaw - val oldYaw = entity.yaw - val oldPitch = entity.pitch - val oldPrevHeadYaw = entity.prevHeadYaw - val oldHeadYaw = entity.headYaw - entity.bodyYaw = 180.0f + targetYaw * 20.0f - entity.yaw = 180.0f + targetYaw * 40.0f - entity.pitch = -targetPitch * 20.0f - entity.headYaw = entity.yaw - entity.prevHeadYaw = entity.yaw - val vector3f = Vector3f(0.0f, entity.height / 2.0f + bottomOffset, 0.0f) - InventoryScreen.drawEntity( - context, - centerX, - centerY, - size, - vector3f, - rotateToFaceTheFront, - rotateToFaceTheCamera, - entity - ) - entity.bodyYaw = oldBodyYaw - entity.yaw = oldYaw - entity.pitch = oldPitch - entity.prevHeadYaw = oldPrevHeadYaw - entity.headYaw = oldHeadYaw - context.disableScissor() - } - - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt deleted file mode 100644 index 2e49072..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt +++ /dev/null @@ -1,35 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import me.shedaniel.math.Dimension -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.Element -import net.minecraft.entity.LivingEntity - -class EntityWidget(val entity: LivingEntity, val point: Point) : WidgetWithBounds() { - override fun children(): List<Element> { - return emptyList() - } - - var hasErrored = false - - override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - try { - if (!hasErrored) - EntityRenderer.renderEntity(entity, context, point.x, point.y, mouseX.toFloat(), mouseY.toFloat()) - } catch (ex: Exception) { - EntityRenderer.logger.error("Failed to render constructed entity: $entity", ex) - hasErrored = true - } - if (hasErrored) { - context.fill(point.x, point.y, point.x + 50, point.y + 80, 0xFFAA2222.toInt()) - } - } - - override fun getBounds(): Rectangle { - return Rectangle(point, Dimension(50, 80)) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt deleted file mode 100644 index f354d5a..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt +++ /dev/null @@ -1,488 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.mojang.datafixers.util.Pair -import com.mojang.serialization.Lifecycle -import java.util.* -import java.util.function.BooleanSupplier -import java.util.function.Consumer -import java.util.stream.Stream -import kotlin.jvm.optionals.getOrNull -import kotlin.streams.asSequence -import net.minecraft.block.Block -import net.minecraft.block.BlockState -import net.minecraft.component.type.MapIdComponent -import net.minecraft.entity.Entity -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.fluid.Fluid -import net.minecraft.item.map.MapState -import net.minecraft.recipe.BrewingRecipeRegistry -import net.minecraft.recipe.Ingredient -import net.minecraft.recipe.RecipeManager -import net.minecraft.registry.BuiltinRegistries -import net.minecraft.registry.DynamicRegistryManager -import net.minecraft.registry.Registry -import net.minecraft.registry.RegistryKey -import net.minecraft.registry.RegistryKeys -import net.minecraft.registry.RegistryWrapper -import net.minecraft.registry.entry.RegistryEntry -import net.minecraft.registry.entry.RegistryEntryInfo -import net.minecraft.registry.entry.RegistryEntryList -import net.minecraft.registry.entry.RegistryEntryOwner -import net.minecraft.registry.tag.TagKey -import net.minecraft.resource.featuretoggle.FeatureFlags -import net.minecraft.resource.featuretoggle.FeatureSet -import net.minecraft.scoreboard.Scoreboard -import net.minecraft.sound.SoundCategory -import net.minecraft.sound.SoundEvent -import net.minecraft.util.Identifier -import net.minecraft.util.TypeFilter -import net.minecraft.util.function.LazyIterationConsumer -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Box -import net.minecraft.util.math.ChunkPos -import net.minecraft.util.math.Direction -import net.minecraft.util.math.Vec3d -import net.minecraft.util.math.random.Random -import net.minecraft.util.profiler.DummyProfiler -import net.minecraft.world.BlockView -import net.minecraft.world.Difficulty -import net.minecraft.world.GameRules -import net.minecraft.world.MutableWorldProperties -import net.minecraft.world.World -import net.minecraft.world.biome.Biome -import net.minecraft.world.biome.BiomeKeys -import net.minecraft.world.chunk.Chunk -import net.minecraft.world.chunk.ChunkManager -import net.minecraft.world.chunk.ChunkStatus -import net.minecraft.world.chunk.EmptyChunk -import net.minecraft.world.chunk.light.LightingProvider -import net.minecraft.world.entity.EntityLookup -import net.minecraft.world.event.GameEvent -import net.minecraft.world.tick.OrderedTick -import net.minecraft.world.tick.QueryableTickScheduler -import net.minecraft.world.tick.TickManager - -fun <T> makeRegistry(registryWrapper: RegistryWrapper.Impl<T>, key: RegistryKey<out Registry<T>>): Registry<T> { - val inverseLookup = registryWrapper.streamEntries() - .asSequence().map { it.value() to it.registryKey() } - .toMap() - val idLookup = registryWrapper.streamEntries() - .asSequence() - .map { it.registryKey() } - .withIndex() - .associate { it.value to it.index } - val map = registryWrapper.streamEntries().asSequence().map { it.registryKey() to it.value() }.toMap(mutableMapOf()) - val inverseIdLookup = idLookup.asIterable().associate { (k, v) -> v to k } - return object : Registry<T> { - override fun get(key: RegistryKey<T>?): T? { - return registryWrapper.getOptional(key).getOrNull()?.value() - } - - override fun iterator(): MutableIterator<T> { - return object : MutableIterator<T> { - val iterator = registryWrapper.streamEntries().iterator() - override fun hasNext(): Boolean { - return iterator.hasNext() - } - - override fun next(): T { - return iterator.next().value() - } - - override fun remove() { - TODO("Not yet implemented") - } - } - } - - override fun getRawId(value: T?): Int { - return idLookup[inverseLookup[value ?: return -1] ?: return -1] ?: return -1 - } - - override fun get(id: Identifier?): T? { - return get(RegistryKey.of(key, id)) - } - - override fun get(index: Int): T? { - return get(inverseIdLookup[index] ?: return null) - } - - override fun size(): Int { - return idLookup.size - } - - override fun getKey(): RegistryKey<out Registry<T>> { - return key - } - - override fun getEntryInfo(key: RegistryKey<T>?): Optional<RegistryEntryInfo> { - TODO("Not yet implemented") - } - - override fun getLifecycle(): Lifecycle { - return Lifecycle.stable() - } - - override fun getDefaultEntry(): Optional<RegistryEntry.Reference<T>> { - return Optional.empty() - } - - override fun getIds(): MutableSet<Identifier> { - return idLookup.keys.mapTo(mutableSetOf()) { it.value } - } - - override fun getEntrySet(): MutableSet<MutableMap.MutableEntry<RegistryKey<T>, T>> { - return map.entries - } - - override fun getKeys(): MutableSet<RegistryKey<T>> { - return map.keys - } - - override fun getRandom(random: Random?): Optional<RegistryEntry.Reference<T>> { - return registryWrapper.streamEntries().findFirst() - } - - override fun containsId(id: Identifier?): Boolean { - return idLookup.containsKey(RegistryKey.of(key, id ?: return false)) - } - - override fun freeze(): Registry<T> { - return this - } - - override fun getEntry(rawId: Int): Optional<RegistryEntry.Reference<T>> { - val x = inverseIdLookup[rawId] ?: return Optional.empty() - return Optional.of(RegistryEntry.Reference.standAlone(registryWrapper, x)) - } - - override fun streamEntries(): Stream<RegistryEntry.Reference<T>> { - return registryWrapper.streamEntries() - } - - override fun streamTagsAndEntries(): Stream<Pair<TagKey<T>, RegistryEntryList.Named<T>>> { - return streamTags().map { Pair(it, getOrCreateEntryList(it)) } - } - - override fun streamTags(): Stream<TagKey<T>> { - return registryWrapper.streamTagKeys() - } - - override fun clearTags() { - } - - override fun getEntryOwner(): RegistryEntryOwner<T> { - return registryWrapper - } - - override fun getReadOnlyWrapper(): RegistryWrapper.Impl<T> { - return registryWrapper - } - - override fun populateTags(tagEntries: MutableMap<TagKey<T>, MutableList<RegistryEntry<T>>>?) { - } - - override fun getOrCreateEntryList(tag: TagKey<T>?): RegistryEntryList.Named<T> { - return getEntryList(tag).orElseGet { RegistryEntryList.of(registryWrapper, tag) } - } - - override fun getEntryList(tag: TagKey<T>?): Optional<RegistryEntryList.Named<T>> { - return registryWrapper.getOptional(tag ?: return Optional.empty()) - } - - override fun getEntry(value: T): RegistryEntry<T> { - return registryWrapper.getOptional(inverseLookup[value]!!).get() - } - - override fun getEntry(key: RegistryKey<T>?): Optional<RegistryEntry.Reference<T>> { - return registryWrapper.getOptional(key ?: return Optional.empty()) - } - - override fun getEntry(id: Identifier?): Optional<RegistryEntry.Reference<T>> { - TODO("Not yet implemented") - } - - override fun createEntry(value: T): RegistryEntry.Reference<T> { - TODO("Not yet implemented") - } - - override fun contains(key: RegistryKey<T>?): Boolean { - return getEntry(key).isPresent - } - - override fun getId(value: T): Identifier? { - return (inverseLookup[value] ?: return null).value - } - - override fun getKey(entry: T): Optional<RegistryKey<T>> { - return Optional.ofNullable(inverseLookup[entry ?: return Optional.empty()]) - } - } -} - -fun createDynamicRegistry(): DynamicRegistryManager.Immutable { - val wrapperLookup = BuiltinRegistries.createWrapperLookup() - return object : DynamicRegistryManager.Immutable { - override fun <E : Any?> getOptional(key: RegistryKey<out Registry<out E>>): Optional<Registry<E>> { - val lookup = wrapperLookup.getOptionalWrapper(key).getOrNull() ?: return Optional.empty() - val registry = makeRegistry(lookup, key as RegistryKey<out Registry<E>>) - return Optional.of(registry) - } - - fun <T> entry(reg: RegistryKey<out Registry<T>>): DynamicRegistryManager.Entry<T> { - return DynamicRegistryManager.Entry(reg, getOptional(reg).get()) - } - - override fun streamAllRegistries(): Stream<DynamicRegistryManager.Entry<*>> { - return wrapperLookup.streamAllRegistryKeys() - .map { entry(it as RegistryKey<out Registry<Any>>) } - } - } -} - -class FakeWorld( - registries: DynamicRegistryManager.Immutable = createDynamicRegistry(), -) : World( - Properties, - RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")), - registries, - registries[RegistryKeys.DIMENSION_TYPE].entryOf( - RegistryKey.of( - RegistryKeys.DIMENSION_TYPE, - Identifier.of("minecraft", "overworld") - ) - ), - { DummyProfiler.INSTANCE }, - true, - false, - 0, 0 -) { - object Properties : MutableWorldProperties { - override fun getSpawnPos(): BlockPos { - return BlockPos.ORIGIN - } - - override fun getSpawnAngle(): Float { - return 0F - } - - override fun getTime(): Long { - return 0 - } - - override fun getTimeOfDay(): Long { - return 0 - } - - override fun isThundering(): Boolean { - return false - } - - override fun isRaining(): Boolean { - return false - } - - override fun setRaining(raining: Boolean) { - } - - override fun isHardcore(): Boolean { - return false - } - - override fun getGameRules(): GameRules { - return GameRules() - } - - override fun getDifficulty(): Difficulty { - return Difficulty.HARD - } - - override fun isDifficultyLocked(): Boolean { - return false - } - - override fun setSpawnPos(pos: BlockPos?, angle: Float) {} - } - - override fun getPlayers(): List<PlayerEntity> { - return emptyList() - } - - override fun getBrightness(direction: Direction?, shaded: Boolean): Float { - return 1f - } - - override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> { - return registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS) - } - - override fun getEnabledFeatures(): FeatureSet { - return FeatureFlags.VANILLA_FEATURES - } - - class FakeTickScheduler<T> : QueryableTickScheduler<T> { - override fun scheduleTick(orderedTick: OrderedTick<T>?) { - } - - override fun isQueued(pos: BlockPos?, type: T): Boolean { - return true - } - - override fun getTickCount(): Int { - return 0 - } - - override fun isTicking(pos: BlockPos?, type: T): Boolean { - return true - } - - } - - override fun getBlockTickScheduler(): QueryableTickScheduler<Block> { - return FakeTickScheduler() - } - - override fun getFluidTickScheduler(): QueryableTickScheduler<Fluid> { - return FakeTickScheduler() - } - - - class FakeChunkManager(val world: FakeWorld) : ChunkManager() { - override fun getChunk(x: Int, z: Int, leastStatus: ChunkStatus?, create: Boolean): Chunk { - return EmptyChunk( - world, - ChunkPos(x, z), - world.registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS) - ) - } - - override fun getWorld(): BlockView { - return world - } - - override fun tick(shouldKeepTicking: BooleanSupplier?, tickChunks: Boolean) { - } - - override fun getDebugString(): String { - return "FakeChunkManager" - } - - override fun getLoadedChunkCount(): Int { - return 0 - } - - override fun getLightingProvider(): LightingProvider { - return FakeLightingProvider(this) - } - } - - class FakeLightingProvider(chunkManager: FakeChunkManager) : LightingProvider(chunkManager, false, false) - - override fun getChunkManager(): ChunkManager { - return FakeChunkManager(this) - } - - override fun playSound( - source: PlayerEntity?, - x: Double, - y: Double, - z: Double, - sound: RegistryEntry<SoundEvent>?, - category: SoundCategory?, - volume: Float, - pitch: Float, - seed: Long - ) { - } - - override fun syncWorldEvent(player: PlayerEntity?, eventId: Int, pos: BlockPos?, data: Int) { - } - - override fun emitGameEvent(event: RegistryEntry<GameEvent>?, emitterPos: Vec3d?, emitter: GameEvent.Emitter?) { - } - - override fun updateListeners(pos: BlockPos?, oldState: BlockState?, newState: BlockState?, flags: Int) { - } - - override fun playSoundFromEntity( - source: PlayerEntity?, - entity: Entity?, - sound: RegistryEntry<SoundEvent>?, - category: SoundCategory?, - volume: Float, - pitch: Float, - seed: Long - ) { - } - - override fun asString(): String { - return "FakeWorld" - } - - override fun getEntityById(id: Int): Entity? { - return null - } - - override fun getTickManager(): TickManager { - return TickManager() - } - - override fun getMapState(id: MapIdComponent?): MapState? { - return null - } - - override fun putMapState(id: MapIdComponent?, state: MapState?) { - } - - override fun increaseAndGetMapId(): MapIdComponent { - return MapIdComponent(0) - } - - override fun setBlockBreakingInfo(entityId: Int, pos: BlockPos?, progress: Int) { - } - - override fun getScoreboard(): Scoreboard { - return Scoreboard() - } - - override fun getRecipeManager(): RecipeManager { - return RecipeManager(registryManager) - } - - object FakeEntityLookup : EntityLookup<Entity> { - override fun get(id: Int): Entity? { - return null - } - - override fun get(uuid: UUID?): Entity? { - return null - } - - override fun iterate(): MutableIterable<Entity> { - return mutableListOf() - } - - override fun <U : Entity?> forEachIntersects( - filter: TypeFilter<Entity, U>?, - box: Box?, - consumer: LazyIterationConsumer<U>? - ) { - } - - override fun forEachIntersects(box: Box?, action: Consumer<Entity>?) { - } - - override fun <U : Entity?> forEach(filter: TypeFilter<Entity, U>?, consumer: LazyIterationConsumer<U>?) { - } - - } - - override fun getEntityLookup(): EntityLookup<Entity> { - return FakeEntityLookup - } - - override fun getBrewingRecipeRegistry(): BrewingRecipeRegistry { - return BrewingRecipeRegistry.EMPTY - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/GuiPlayer.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/GuiPlayer.kt deleted file mode 100644 index d00b44d..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/GuiPlayer.kt +++ /dev/null @@ -1,54 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.mojang.authlib.GameProfile -import java.util.* -import net.minecraft.client.network.AbstractClientPlayerEntity -import net.minecraft.client.util.DefaultSkinHelper -import net.minecraft.client.util.SkinTextures -import net.minecraft.client.util.SkinTextures.Model -import net.minecraft.client.world.ClientWorld -import net.minecraft.util.Identifier -import net.minecraft.util.math.BlockPos -import net.minecraft.world.World - -/** - * @see moe.nea.firmament.init.EarlyRiser - */ -fun makeGuiPlayer(world: FakeWorld): GuiPlayer { - val constructor = GuiPlayer::class.java.getDeclaredConstructor( - World::class.java, - BlockPos::class.java, - Float::class.javaPrimitiveType, - GameProfile::class.java - ) - return constructor.newInstance(world, BlockPos.ORIGIN, 0F, GameProfile(UUID.randomUUID(), "Linnea")) -} - -class GuiPlayer(world: ClientWorld?, profile: GameProfile?) : AbstractClientPlayerEntity(world, profile) { - override fun isSpectator(): Boolean { - return false - } - - override fun isCreative(): Boolean { - return false - } - - override fun shouldRenderName(): Boolean { - return false - } - - var skinTexture: Identifier = DefaultSkinHelper.getSkinTextures(this.getUuid()).texture - var capeTexture: Identifier? = null - var model: Model = Model.WIDE - override fun getSkinTextures(): SkinTextures { - return SkinTextures( - skinTexture, - null, - capeTexture, - null, - model, - true - ) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyAge.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyAge.kt deleted file mode 100644 index a65c368..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyAge.kt +++ /dev/null @@ -1,25 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.decoration.ArmorStandEntity -import net.minecraft.entity.mob.ZombieEntity -import net.minecraft.entity.passive.PassiveEntity - -object ModifyAge : EntityModifier { - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - val isBaby = info["baby"]?.asBoolean ?: false - if (entity is PassiveEntity) { - entity.breedingAge = if (isBaby) -1 else 1 - } else if (entity is ZombieEntity) { - entity.isBaby = isBaby - } else if (entity is ArmorStandEntity) { - entity.isSmall = isBaby - } else { - error("Cannot set age for $entity") - } - return entity - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyCharged.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyCharged.kt deleted file mode 100644 index d22f6e3..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyCharged.kt +++ /dev/null @@ -1,14 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.mob.CreeperEntity - -object ModifyCharged : EntityModifier { - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - require(entity is CreeperEntity) - entity.dataTracker.set(CreeperEntity.CHARGED, true) - return entity - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyEquipment.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyEquipment.kt deleted file mode 100644 index 73e450e..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyEquipment.kt +++ /dev/null @@ -1,55 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import net.minecraft.component.DataComponentTypes -import net.minecraft.component.type.DyedColorComponent -import net.minecraft.entity.EquipmentSlot -import net.minecraft.entity.LivingEntity -import net.minecraft.item.ArmorItem -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import moe.nea.firmament.rei.SBItemStack -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.item.setEncodedSkullOwner -import moe.nea.firmament.util.item.zeroUUID - -object ModifyEquipment : EntityModifier { - val names = mapOf( - "hand" to EquipmentSlot.MAINHAND, - "helmet" to EquipmentSlot.HEAD, - "chestplate" to EquipmentSlot.CHEST, - "leggings" to EquipmentSlot.LEGS, - "feet" to EquipmentSlot.FEET, - ) - - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - names.forEach { (key, slot) -> - info[key]?.let { - entity.equipStack(slot, createItem(it.asString)) - } - } - return entity - } - - private fun createItem(item: String): ItemStack { - val split = item.split("#") - if (split.size != 2) return SBItemStack(SkyblockId(item)).asImmutableItemStack() - val (type, data) = split - return when (type) { - "SKULL" -> ItemStack(Items.PLAYER_HEAD).also { it.setEncodedSkullOwner(zeroUUID, data) } - "LEATHER_LEGGINGS" -> coloredLeatherArmor(Items.LEATHER_LEGGINGS, data) - "LEATHER_BOOTS" -> coloredLeatherArmor(Items.LEATHER_BOOTS, data) - "LEATHER_HELMET" -> coloredLeatherArmor(Items.LEATHER_HELMET, data) - "LEATHER_CHESTPLATE" -> coloredLeatherArmor(Items.LEATHER_CHESTPLATE, data) - else -> error("Unknown leather piece: $type") - } - } - - private fun coloredLeatherArmor(leatherArmor: Item, data: String): ItemStack { - val stack = ItemStack(leatherArmor) - stack.set(DataComponentTypes.DYED_COLOR, DyedColorComponent(data.toInt(16), false)) - return stack - } -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyHorse.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyHorse.kt deleted file mode 100644 index 8ac011b..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyHorse.kt +++ /dev/null @@ -1,61 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonNull -import com.google.gson.JsonObject -import kotlin.experimental.and -import kotlin.experimental.inv -import kotlin.experimental.or -import net.minecraft.entity.EntityType -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.passive.AbstractHorseEntity -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import moe.nea.firmament.gui.entity.EntityRenderer.fakeWorld - -object ModifyHorse : EntityModifier { - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - require(entity is AbstractHorseEntity) - var entity: AbstractHorseEntity = entity - info["kind"]?.let { - entity = when (it.asString) { - "skeleton" -> EntityType.SKELETON_HORSE.create(fakeWorld)!! - "zombie" -> EntityType.ZOMBIE_HORSE.create(fakeWorld)!! - "mule" -> EntityType.MULE.create(fakeWorld)!! - "donkey" -> EntityType.DONKEY.create(fakeWorld)!! - "horse" -> EntityType.HORSE.create(fakeWorld)!! - else -> error("Unknown horse kind $it") - } - } - info["armor"]?.let { - if (it is JsonNull) { - entity.setHorseArmor(ItemStack.EMPTY) - } else { - when (it.asString) { - "iron" -> entity.setHorseArmor(ItemStack(Items.IRON_HORSE_ARMOR)) - "golden" -> entity.setHorseArmor(ItemStack(Items.GOLDEN_HORSE_ARMOR)) - "diamond" -> entity.setHorseArmor(ItemStack(Items.DIAMOND_HORSE_ARMOR)) - else -> error("Unknown horse armor $it") - } - } - } - info["saddled"]?.let { - entity.setIsSaddled(it.asBoolean) - } - return entity - } - -} - -fun AbstractHorseEntity.setIsSaddled(shouldBeSaddled: Boolean) { - val oldFlag = dataTracker.get(AbstractHorseEntity.HORSE_FLAGS) - dataTracker.set( - AbstractHorseEntity.HORSE_FLAGS, - if (shouldBeSaddled) oldFlag or AbstractHorseEntity.SADDLED_FLAG.toByte() - else oldFlag and AbstractHorseEntity.SADDLED_FLAG.toByte().inv() - ) -} - -fun AbstractHorseEntity.setHorseArmor(itemStack: ItemStack) { - items.setStack(1, itemStack) -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyInvisible.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyInvisible.kt deleted file mode 100644 index 8d36991..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyInvisible.kt +++ /dev/null @@ -1,13 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import net.minecraft.entity.LivingEntity - -object ModifyInvisible : EntityModifier { - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - entity.isInvisible = info.get("invisible")?.asBoolean ?: true - return entity - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyName.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyName.kt deleted file mode 100644 index a03da96..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyName.kt +++ /dev/null @@ -1,14 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import net.minecraft.entity.LivingEntity -import net.minecraft.text.Text - -object ModifyName : EntityModifier { - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - entity.customName = Text.literal(info.get("name").asString) - return entity - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyPlayerSkin.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyPlayerSkin.kt deleted file mode 100644 index 28f0070..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyPlayerSkin.kt +++ /dev/null @@ -1,47 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import kotlin.experimental.and -import kotlin.experimental.or -import net.minecraft.client.util.SkinTextures -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.entity.player.PlayerModelPart -import net.minecraft.util.Identifier - -object ModifyPlayerSkin : EntityModifier { - val playerModelPartIndex = PlayerModelPart.entries.associateBy { it.getName() } - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - require(entity is GuiPlayer) - info["cape"]?.let { - entity.capeTexture = Identifier.of(it.asString) - } - info["skin"]?.let { - entity.skinTexture = Identifier.of(it.asString) - } - info["slim"]?.let { - entity.model = if (it.asBoolean) SkinTextures.Model.SLIM else SkinTextures.Model.WIDE - } - info["parts"]?.let { - var trackedData = entity.dataTracker.get(PlayerEntity.PLAYER_MODEL_PARTS) - if (it is JsonPrimitive && it.isBoolean) { - trackedData = (if (it.asBoolean) -1 else 0).toByte() - } else { - val obj = it.asJsonObject - for ((k, v) in obj.entrySet()) { - val part = playerModelPartIndex[k]!! - trackedData = if (v.asBoolean) { - trackedData and (part.bitFlag.inv().toByte()) - } else { - trackedData or (part.bitFlag.toByte()) - } - } - } - entity.dataTracker.set(PlayerEntity.PLAYER_MODEL_PARTS, trackedData) - } - return entity - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyRiding.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyRiding.kt deleted file mode 100644 index 5c4c78d..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyRiding.kt +++ /dev/null @@ -1,15 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import net.minecraft.entity.LivingEntity - -object ModifyRiding : EntityModifier { - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - val newEntity = EntityRenderer.constructEntity(info) - require(newEntity != null) - newEntity.startRiding(entity, true) - return entity - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyWither.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyWither.kt deleted file mode 100644 index 6083d88..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/entity/ModifyWither.kt +++ /dev/null @@ -1,20 +0,0 @@ - -package moe.nea.firmament.gui.entity - -import com.google.gson.JsonObject -import net.minecraft.entity.LivingEntity -import net.minecraft.entity.boss.WitherEntity - -object ModifyWither : EntityModifier { - override fun apply(entity: LivingEntity, info: JsonObject): LivingEntity { - require(entity is WitherEntity) - info["tiny"]?.let { - entity.setInvulTimer(if (it.asBoolean) 800 else 0) - } - info["armored"]?.let { - entity.health = if (it.asBoolean) 1F else entity.maxHealth - } - return entity - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/gui/hud/MoulConfigHud.kt b/src/main/kotlin/moe/nea/firmament/gui/hud/MoulConfigHud.kt deleted file mode 100644 index e77d9af..0000000 --- a/src/main/kotlin/moe/nea/firmament/gui/hud/MoulConfigHud.kt +++ /dev/null @@ -1,66 +0,0 @@ - -package moe.nea.firmament.gui.hud - -import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper -import io.github.notenoughupdates.moulconfig.gui.GuiContext -import io.github.notenoughupdates.moulconfig.gui.component.TextComponent -import net.minecraft.resource.ResourceManager -import net.minecraft.resource.SynchronousResourceReloader -import moe.nea.firmament.events.FinalizeResourceManagerEvent -import moe.nea.firmament.events.HudRenderEvent -import moe.nea.firmament.gui.config.HudMeta -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.MoulConfigUtils - -abstract class MoulConfigHud( - val name: String, - val hudMeta: HudMeta, -) { - companion object { - private val componentWrapper by lazy { - object : GuiComponentWrapper(GuiContext(TextComponent("§cERROR"))) { - init { - this.client = MC.instance - } - } - } - } - - private var fragment: GuiContext? = null - - fun forceInit() { - } - - open fun shouldRender(): Boolean { - return true - } - - init { - require(name.matches("^[a-z_/]+$".toRegex())) - HudRenderEvent.subscribe { - if (!shouldRender()) return@subscribe - val renderContext = componentWrapper.createContext(it.context) - if (fragment == null) - loadFragment() - it.context.matrices.push() - hudMeta.applyTransformations(it.context.matrices) - val renderContextTranslated = - renderContext.translated(hudMeta.absoluteX, hudMeta.absoluteY, hudMeta.width, hudMeta.height) - .scaled(hudMeta.scale) - fragment!!.root.render(renderContextTranslated) - it.context.matrices.pop() - } - FinalizeResourceManagerEvent.subscribe { - MC.resourceManager.registerReloader(object : SynchronousResourceReloader { - override fun reload(manager: ResourceManager?) { - fragment = null - } - }) - } - } - - fun loadFragment() { - fragment = MoulConfigUtils.loadGui(name, this) - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/jarvis/JarvisIntegration.kt b/src/main/kotlin/moe/nea/firmament/jarvis/JarvisIntegration.kt deleted file mode 100644 index 96f47f7..0000000 --- a/src/main/kotlin/moe/nea/firmament/jarvis/JarvisIntegration.kt +++ /dev/null @@ -1,64 +0,0 @@ - - -package moe.nea.firmament.jarvis - -import moe.nea.jarvis.api.Jarvis -import moe.nea.jarvis.api.JarvisConfigOption -import moe.nea.jarvis.api.JarvisHud -import moe.nea.jarvis.api.JarvisPlugin -import net.minecraft.client.gui.screen.Screen -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.features.FeatureManager -import moe.nea.firmament.gui.config.HudMeta -import moe.nea.firmament.gui.config.HudMetaHandler -import moe.nea.firmament.repo.RepoManager - -class JarvisIntegration : JarvisPlugin { - override fun getModId(): String = - Firmament.MOD_ID - - companion object { - lateinit var jarvis: Jarvis - } - - override fun onInitialize(jarvis: Jarvis) { - Companion.jarvis = jarvis - } - - val configs - get() = listOf( - RepoManager.Config - ) + FeatureManager.allFeatures.mapNotNull { it.config } - - - override fun getAllHuds(): List<JarvisHud> { - return configs.flatMap { config -> - config.sortedOptions.mapNotNull { if (it.handler is HudMetaHandler) it.value as HudMeta else null } - } - } - - override fun onHudEditorClosed() { - configs.forEach { it.save() } - } - - override fun getAllConfigOptions(): List<JarvisConfigOption> { - return configs.flatMap { config -> - config.sortedOptions.map { - object : JarvisConfigOption { - override fun title(): Text { - return it.labelText - } - - override fun description(): List<Text> { - return emptyList() - } - - override fun jumpTo(parentScreen: Screen?): Screen { - return config.getConfigEditor(parentScreen) - } - } - } - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/keybindings/FirmamentKeyBindings.kt b/src/main/kotlin/moe/nea/firmament/keybindings/FirmamentKeyBindings.kt deleted file mode 100644 index e2bed8d..0000000 --- a/src/main/kotlin/moe/nea/firmament/keybindings/FirmamentKeyBindings.kt +++ /dev/null @@ -1,26 +0,0 @@ - - -package moe.nea.firmament.keybindings - -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper -import net.minecraft.client.option.KeyBinding -import net.minecraft.client.util.InputUtil -import moe.nea.firmament.gui.config.KeyBindingHandler -import moe.nea.firmament.gui.config.ManagedOption - -object FirmamentKeyBindings { - fun registerKeyBinding(name: String, config: ManagedOption<SavedKeyBinding>) { - val vanillaKeyBinding = KeyBindingHelper.registerKeyBinding( - KeyBinding( - name, - InputUtil.Type.KEYSYM, - -1, - "firmament.key.category" - ) - ) - keyBindings[vanillaKeyBinding] = config - } - - val keyBindings = mutableMapOf<KeyBinding, ManagedOption<SavedKeyBinding>>() - -} diff --git a/src/main/kotlin/moe/nea/firmament/keybindings/IKeyBinding.kt b/src/main/kotlin/moe/nea/firmament/keybindings/IKeyBinding.kt deleted file mode 100644 index 1975361..0000000 --- a/src/main/kotlin/moe/nea/firmament/keybindings/IKeyBinding.kt +++ /dev/null @@ -1,29 +0,0 @@ - - -package moe.nea.firmament.keybindings - -import net.minecraft.client.option.KeyBinding - -interface IKeyBinding { - fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean - - fun withModifiers(wantedModifiers: Int): IKeyBinding { - val old = this - return object : IKeyBinding { - override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { - return old.matches(keyCode, scanCode, modifiers) && (modifiers and wantedModifiers) == wantedModifiers - } - } - } - - companion object { - fun minecraft(keyBinding: KeyBinding) = object : IKeyBinding { - override fun matches(keyCode: Int, scanCode: Int, modifiers: Int) = - keyBinding.matchesKey(keyCode, scanCode) - } - - fun ofKeyCode(wantedKeyCode: Int) = object : IKeyBinding { - override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean = keyCode == wantedKeyCode - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt b/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt deleted file mode 100644 index 8607fd0..0000000 --- a/src/main/kotlin/moe/nea/firmament/keybindings/SavedKeyBinding.kt +++ /dev/null @@ -1,106 +0,0 @@ - - -package moe.nea.firmament.keybindings - -import org.lwjgl.glfw.GLFW -import kotlinx.serialization.Serializable -import net.minecraft.client.MinecraftClient -import net.minecraft.client.util.InputUtil -import net.minecraft.text.Text -import moe.nea.firmament.util.MC - -@Serializable -data class SavedKeyBinding( - val keyCode: Int, - val shift: Boolean = false, - val ctrl: Boolean = false, - val alt: Boolean = false, -) : IKeyBinding { - val isBound: Boolean get() = keyCode != GLFW.GLFW_KEY_UNKNOWN - - constructor(keyCode: Int, mods: Triple<Boolean, Boolean, Boolean>) : this( - keyCode, - mods.first && keyCode != GLFW.GLFW_KEY_LEFT_SHIFT && keyCode != GLFW.GLFW_KEY_RIGHT_SHIFT, - mods.second && keyCode != GLFW.GLFW_KEY_LEFT_CONTROL && keyCode != GLFW.GLFW_KEY_RIGHT_CONTROL, - mods.third && keyCode != GLFW.GLFW_KEY_LEFT_ALT && keyCode != GLFW.GLFW_KEY_RIGHT_ALT, - ) - - constructor(keyCode: Int, mods: Int) : this(keyCode, getMods(mods)) - - companion object { - fun getMods(modifiers: Int): Triple<Boolean, Boolean, Boolean> { - return Triple( - modifiers and GLFW.GLFW_MOD_SHIFT != 0, - modifiers and GLFW.GLFW_MOD_CONTROL != 0, - modifiers and GLFW.GLFW_MOD_ALT != 0 - ) - } - - fun getModInt(): Int { - val h = MC.window.handle - val ctrl = if (MinecraftClient.IS_SYSTEM_MAC) { - InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SUPER) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SUPER) - } else InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_CONTROL) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_CONTROL) - val shift = isShiftDown() - val alt = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_ALT) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_ALT) - var mods = 0 - if (ctrl) mods = mods or GLFW.GLFW_MOD_CONTROL - if (shift) mods = mods or GLFW.GLFW_MOD_SHIFT - if (alt) mods = mods or GLFW.GLFW_MOD_ALT - return mods - } - - private val h get() = MC.window.handle - fun isShiftDown() = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SHIFT) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SHIFT) - - } - - fun isPressed(atLeast: Boolean = false): Boolean { - if (!isBound) return false - val h = MC.window.handle - if (!InputUtil.isKeyPressed(h, keyCode)) return false - - val ctrl = if (MinecraftClient.IS_SYSTEM_MAC) { - InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SUPER) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SUPER) - } else InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_CONTROL) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_CONTROL) - val shift = isShiftDown() - val alt = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_ALT) - || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_ALT) - if (atLeast) - return (ctrl >= this.ctrl) && - (alt >= this.alt) && - (shift >= this.shift) - - return (ctrl == this.ctrl) && - (alt == this.alt) && - (shift == this.shift) - } - - override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { - if (this.keyCode == GLFW.GLFW_KEY_UNKNOWN) return false - return keyCode == this.keyCode && getMods(modifiers) == Triple(shift, ctrl, alt) - } - - fun format(): Text { - val stroke = Text.literal("") - if (ctrl) { - stroke.append("CTRL + ") - } - if (alt) { - stroke.append("ALT + ") - } - if (shift) { - stroke.append("SHIFT + ") // TODO: translations? - } - - stroke.append(InputUtil.Type.KEYSYM.createFromCode(keyCode).localizedText) - return stroke - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/modmenu/FirmamentModMenuPlugin.kt b/src/main/kotlin/moe/nea/firmament/modmenu/FirmamentModMenuPlugin.kt deleted file mode 100644 index f889bf3..0000000 --- a/src/main/kotlin/moe/nea/firmament/modmenu/FirmamentModMenuPlugin.kt +++ /dev/null @@ -1,14 +0,0 @@ - - -package moe.nea.firmament.modmenu - -import com.terraformersmc.modmenu.api.ConfigScreenFactory -import com.terraformersmc.modmenu.api.ModMenuApi -import moe.nea.firmament.gui.config.AllConfigsGui - -class FirmamentModMenuPlugin : ModMenuApi { - override fun getModConfigScreenFactory(): ConfigScreenFactory<*> { - return ConfigScreenFactory { AllConfigsGui.makeScreen(it) } - } -} - diff --git a/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt b/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt deleted file mode 100644 index b585336..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt +++ /dev/null @@ -1,128 +0,0 @@ - - -package moe.nea.firmament.rei - -import me.shedaniel.rei.api.client.plugins.REIClientPlugin -import me.shedaniel.rei.api.client.registry.category.CategoryRegistry -import me.shedaniel.rei.api.client.registry.display.DisplayRegistry -import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry -import me.shedaniel.rei.api.client.registry.entry.EntryRegistry -import me.shedaniel.rei.api.client.registry.screen.ExclusionZones -import me.shedaniel.rei.api.client.registry.screen.OverlayDecider -import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry -import me.shedaniel.rei.api.client.registry.transfer.TransferHandler -import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry -import me.shedaniel.rei.api.common.entry.EntryStack -import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry -import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes -import net.minecraft.client.gui.screen.Screen -import net.minecraft.client.gui.screen.ingame.GenericContainerScreen -import net.minecraft.client.gui.screen.ingame.HandledScreen -import net.minecraft.item.ItemStack -import net.minecraft.text.Text -import net.minecraft.util.ActionResult -import net.minecraft.util.Identifier -import moe.nea.firmament.events.HandledScreenPushREIEvent -import moe.nea.firmament.features.inventory.CraftingOverlay -import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen -import moe.nea.firmament.rei.recipes.SBCraftingRecipe -import moe.nea.firmament.rei.recipes.SBEssenceUpgradeRecipe -import moe.nea.firmament.rei.recipes.SBForgeRecipe -import moe.nea.firmament.rei.recipes.SBKatRecipe -import moe.nea.firmament.rei.recipes.SBMobDropRecipe -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.skyblockId -import moe.nea.firmament.util.unformattedString - - -class FirmamentReiPlugin : REIClientPlugin { - - companion object { - fun EntryStack<SBItemStack>.asItemEntry(): EntryStack<ItemStack> { - return EntryStack.of(VanillaEntryTypes.ITEM, value.asImmutableItemStack()) - } - - val SKYBLOCK_ITEM_TYPE_ID = Identifier.of("firmament", "skyblockitems") - } - - override fun registerTransferHandlers(registry: TransferHandlerRegistry) { - registry.register(TransferHandler { context -> - val screen = context.containerScreen - val display = context.display - if (display !is SBCraftingRecipe || screen !is GenericContainerScreen || screen.title?.unformattedString != "Craft Item") { - return@TransferHandler TransferHandler.Result.createNotApplicable() - } - if (context.isActuallyCrafting) - CraftingOverlay.setOverlay(screen, display) - return@TransferHandler TransferHandler.Result.createSuccessful().blocksFurtherHandling(true) - }) - } - - override fun registerEntryTypes(registry: EntryTypeRegistry) { - registry.register(SKYBLOCK_ITEM_TYPE_ID, SBItemEntryDefinition) - } - - override fun registerCategories(registry: CategoryRegistry) { - registry.add(SBCraftingRecipe.Category) - registry.add(SBForgeRecipe.Category) - registry.add(SBMobDropRecipe.Category) - registry.add(SBKatRecipe.Category) - registry.add(SBEssenceUpgradeRecipe.Category) - } - - override fun registerExclusionZones(zones: ExclusionZones) { - zones.register(HandledScreen::class.java) { HandledScreenPushREIEvent.publish(HandledScreenPushREIEvent(it)).rectangles } - zones.register(StorageOverlayScreen::class.java) { it.getBounds() } - } - - override fun registerDisplays(registry: DisplayRegistry) { - registry.registerDisplayGenerator( - SBCraftingRecipe.Category.catIdentifier, - SkyblockCraftingRecipeDynamicGenerator) - registry.registerDisplayGenerator( - SBForgeRecipe.Category.categoryIdentifier, - SkyblockForgeRecipeDynamicGenerator) - registry.registerDisplayGenerator( - SBMobDropRecipe.Category.categoryIdentifier, - SkyblockMobDropRecipeDynamicGenerator) - registry.registerDisplayGenerator( - SBKatRecipe.Category.categoryIdentifier, - SkyblockKatRecipeDynamicGenerator) - registry.registerDisplayGenerator( - SBEssenceUpgradeRecipe.Category.categoryIdentifier, - SkyblockEssenceRecipeDynamicGenerator - ) - } - - override fun registerCollapsibleEntries(registry: CollapsibleEntryRegistry) { - if (!RepoManager.Config.disableItemGroups) - RepoManager.neuRepo.constants.parents.parents - .forEach { (parent, children) -> - registry.group( - SkyblockId(parent).identifier, - Text.literal(RepoManager.getNEUItem(SkyblockId(parent))?.displayName ?: parent), - (children + parent).map { SBItemEntryDefinition.getEntry(SkyblockId(it)) }) - } - } - - override fun registerScreens(registry: ScreenRegistry) { - registry.registerDecider(object : OverlayDecider { - override fun <R : Screen?> isHandingScreen(screen: Class<R>?): Boolean { - return screen == StorageOverlayScreen::class.java - } - - override fun <R : Screen?> shouldScreenBeOverlaid(screen: R): ActionResult { - return ActionResult.SUCCESS - } - }) - registry.registerFocusedStack(SkyblockItemIdFocusedStackProvider) - } - - override fun registerEntries(registry: EntryRegistry) { - registry.removeEntryIf { true } - RepoManager.neuRepo.items?.items?.values?.forEach { neuItem -> - registry.addEntry(SBItemEntryDefinition.getEntry(neuItem.skyblockId)) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntryRenderer.kt b/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntryRenderer.kt deleted file mode 100644 index ba99b30..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntryRenderer.kt +++ /dev/null @@ -1,186 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2018-2023 shedaniel <daniel@shedaniel.me> - * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> - * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> - * - * SPDX-License-Identifier: GPL-3.0-or-later - * SPDX-License-Identifier: MIT - */ - -package moe.nea.firmament.rei - -import com.mojang.blaze3d.platform.GlStateManager.DstFactor -import com.mojang.blaze3d.platform.GlStateManager.SrcFactor -import com.mojang.blaze3d.systems.RenderSystem -import me.shedaniel.math.Rectangle -import me.shedaniel.rei.api.client.entry.renderer.BatchedEntryRenderer -import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer -import me.shedaniel.rei.api.client.gui.widgets.Tooltip -import me.shedaniel.rei.api.client.gui.widgets.TooltipContext -import me.shedaniel.rei.api.common.entry.EntryStack -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.DiffuseLighting -import net.minecraft.client.render.LightmapTextureManager -import net.minecraft.client.render.OverlayTexture -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.model.BakedModel -import net.minecraft.client.render.model.json.ModelTransformationMode -import net.minecraft.client.texture.SpriteAtlasTexture -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.item.tooltip.TooltipType -import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry - -object NEUItemEntryRenderer : EntryRenderer<SBItemStack>, BatchedEntryRenderer<SBItemStack, BakedModel> { - override fun render( - entry: EntryStack<SBItemStack>, - context: DrawContext, - bounds: Rectangle, - mouseX: Int, - mouseY: Int, - delta: Float - ) { - entry.asItemEntry().render(context, bounds, mouseX, mouseY, delta) - } - - val minecraft = MinecraftClient.getInstance() - - override fun getTooltip(entry: EntryStack<SBItemStack>, tooltipContext: TooltipContext): Tooltip? { - val stack = entry.value.asImmutableItemStack() - val lore = stack.getTooltip( - Item.TooltipContext.DEFAULT, - null, - TooltipType.BASIC - ) - return Tooltip.create(lore) - } - - override fun getExtraData(entry: EntryStack<SBItemStack>): BakedModel { - return minecraft.itemRenderer.getModel(entry.asItemEntry().value, minecraft.world, minecraft.player, 0) - } - - override fun getBatchIdentifier(entry: EntryStack<SBItemStack>?, bounds: Rectangle?, extraData: BakedModel): Int { - return 1738923 + if (extraData.isSideLit) 1 else 0 - } - - override fun startBatch( - entry: EntryStack<SBItemStack>, - model: BakedModel, - graphics: DrawContext, - delta: Float - ) { - val modelViewStack = RenderSystem.getModelViewStack() - modelViewStack.pushMatrix() - modelViewStack.scale(20.0f, 20.0f, 1.0f) - RenderSystem.applyModelViewMatrix() - setupGL(model) - } - - fun setupGL(model: BakedModel) { - minecraft.textureManager.getTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE) - .setFilter(false, false) - RenderSystem.setShaderTexture(0, SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE) - RenderSystem.enableBlend() - RenderSystem.blendFunc(SrcFactor.SRC_ALPHA, DstFactor.ONE_MINUS_SRC_ALPHA) - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) - val sideLit = model.isSideLit - if (!sideLit) { - DiffuseLighting.disableGuiDepthLighting() - } - } - - override fun renderBase( - entry: EntryStack<SBItemStack>, - model: BakedModel, - graphics: DrawContext, - immediate: VertexConsumerProvider.Immediate, - bounds: Rectangle, - mouseX: Int, - mouseY: Int, - delta: Float - ) { - if (entry.isEmpty) return - val value = entry.asItemEntry().value - graphics.matrices.push() - graphics.matrices.translate(bounds.centerX.toFloat() / 20.0f, bounds.centerY.toFloat() / 20.0f, 0.0f) - graphics.matrices.scale( - bounds.getWidth().toFloat() / 20.0f, - -(bounds.getWidth() + bounds.getHeight()).toFloat() / 2.0f / 20.0f, - 1.0f - ) - minecraft - .itemRenderer - .renderItem( - value, - ModelTransformationMode.GUI, - false, - graphics.matrices, - immediate, - LightmapTextureManager.MAX_LIGHT_COORDINATE, - OverlayTexture.DEFAULT_UV, - model - ) - graphics.matrices.pop() - - } - - override fun afterBase( - entry: EntryStack<SBItemStack>, - model: BakedModel, - graphics: DrawContext, - delta: Float - ) { - RenderSystem.getModelViewStack().popMatrix() - RenderSystem.applyModelViewMatrix() - this.endGL(model) - } - - fun endGL(model: BakedModel) { - RenderSystem.enableDepthTest() - val sideLit = model.isSideLit - if (!sideLit) { - DiffuseLighting.enableGuiDepthLighting() - } - } - - override fun renderOverlay( - entry: EntryStack<SBItemStack>, - extraData: BakedModel, - graphics: DrawContext, - immediate: VertexConsumerProvider.Immediate, - bounds: Rectangle, - mouseX: Int, - mouseY: Int, - delta: Float - ) { - val modelViewStack = RenderSystem.getModelViewStack() - modelViewStack.pushMatrix() - modelViewStack.mul(graphics.matrices.peek().positionMatrix) - modelViewStack.translate(bounds.x.toFloat(), bounds.y.toFloat(), 0.0f) - modelViewStack.scale( - bounds.width.toFloat() / 16.0f, - -(bounds.getWidth() + bounds.getHeight()).toFloat() / 2.0f / 16.0f, - 1.0f - ) - RenderSystem.applyModelViewMatrix() - renderOverlay(DrawContext(minecraft, graphics.vertexConsumers), entry.asItemEntry()) - modelViewStack.popMatrix() - RenderSystem.applyModelViewMatrix() - } - - fun renderOverlay(graphics: DrawContext, entry: EntryStack<ItemStack>) { - if (!entry.isEmpty) { - graphics.drawItemInSlot(MinecraftClient.getInstance().textRenderer, entry.value, 0, 0, null) - } - } - - override fun endBatch( - entry: EntryStack<SBItemStack>?, - extraData: BakedModel?, - graphics: DrawContext?, - delta: Float - ) { - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntrySerializer.kt b/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntrySerializer.kt deleted file mode 100644 index a35d75f..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/NEUItemEntrySerializer.kt +++ /dev/null @@ -1,29 +0,0 @@ - - -package moe.nea.firmament.rei - -import me.shedaniel.rei.api.common.entry.EntrySerializer -import me.shedaniel.rei.api.common.entry.EntryStack -import net.minecraft.nbt.NbtCompound -import moe.nea.firmament.util.SkyblockId - -object NEUItemEntrySerializer : EntrySerializer<SBItemStack> { - const val SKYBLOCK_ID_ENTRY = "SKYBLOCK_ID" - const val SKYBLOCK_ITEM_COUNT = "SKYBLOCK_ITEM_COUNT" - - override fun supportSaving(): Boolean = true - override fun supportReading(): Boolean = true - - override fun read(tag: NbtCompound): SBItemStack { - val id = SkyblockId(tag.getString(SKYBLOCK_ID_ENTRY)) - val count = if (tag.contains(SKYBLOCK_ITEM_COUNT)) tag.getInt(SKYBLOCK_ITEM_COUNT) else 1 - return SBItemStack(id, count) - } - - override fun save(entry: EntryStack<SBItemStack>, value: SBItemStack): NbtCompound { - return NbtCompound().apply { - putString(SKYBLOCK_ID_ENTRY, value.skyblockId.neuItem) - putInt(SKYBLOCK_ITEM_COUNT, value.getStackSize()) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt b/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt deleted file mode 100644 index 5c6740e..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt +++ /dev/null @@ -1,254 +0,0 @@ - - -package moe.nea.firmament.rei - -import io.github.moulberry.repo.constants.PetNumbers -import io.github.moulberry.repo.data.NEUIngredient -import io.github.moulberry.repo.data.NEUItem -import io.github.moulberry.repo.data.Rarity -import java.util.stream.Stream -import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer -import me.shedaniel.rei.api.common.entry.EntrySerializer -import me.shedaniel.rei.api.common.entry.EntryStack -import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext -import me.shedaniel.rei.api.common.entry.type.EntryDefinition -import me.shedaniel.rei.api.common.entry.type.EntryType -import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes -import net.minecraft.item.ItemStack -import net.minecraft.registry.tag.TagKey -import net.minecraft.text.Text -import net.minecraft.util.Formatting -import net.minecraft.util.Identifier -import moe.nea.firmament.rei.FirmamentReiPlugin.Companion.asItemEntry -import moe.nea.firmament.repo.ExpLadders -import moe.nea.firmament.repo.ItemCache -import moe.nea.firmament.repo.ItemCache.asItemStack -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.FirmFormatters -import moe.nea.firmament.util.HypixelPetInfo -import moe.nea.firmament.util.LegacyFormattingCode -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.appendLore -import moe.nea.firmament.util.item.displayNameAccordingToNbt -import moe.nea.firmament.util.petData -import moe.nea.firmament.util.skyBlockId -import moe.nea.firmament.util.withColor - -// TODO: add in extra data like pet info, into this structure -data class PetData( - val rarity: Rarity, - val petId: String, - val exp: Double, - val isStub: Boolean = false, -) { - companion object { - fun fromHypixel(petInfo: HypixelPetInfo) = PetData( - petInfo.tier, petInfo.type, petInfo.exp, - ) - - fun forLevel(petId: String, rarity: Rarity, level: Int) = PetData( - rarity, petId, ExpLadders.getExpLadder(petId, rarity).getPetExpForLevel(level).toDouble() - ) - } - - val levelData by lazy { ExpLadders.getExpLadder(petId, rarity).getPetLevel(exp) } -} - -data class SBItemStack constructor( - val skyblockId: SkyblockId, - val neuItem: NEUItem?, - private var stackSize: Int, - private var petData: PetData?, - val extraLore: List<Text> = emptyList(), - // TODO: grab this star data from nbt if possible - val stars: Int = 0, -) { - - fun getStackSize() = stackSize - fun setStackSize(newSize: Int) { - this.stackSize = newSize - this.itemStack_ = null - } - - fun getPetData() = petData - fun setPetData(petData: PetData?) { - this.petData = petData - this.itemStack_ = null - } - - constructor(skyblockId: SkyblockId, petData: PetData) : this( - skyblockId, - RepoManager.getNEUItem(skyblockId), - 1, - petData - ) - - constructor(skyblockId: SkyblockId, stackSize: Int = 1) : this( - skyblockId, - RepoManager.getNEUItem(skyblockId), - stackSize, - RepoManager.getPotentialStubPetData(skyblockId) - ) - - private fun injectReplacementDataForPetLevel( - petInfo: PetNumbers, - level: Int, - replacementData: MutableMap<String, String> - ) { - val stats = petInfo.interpolatedStatsAtLevel(level) ?: return - stats.otherNumbers.forEachIndexed { index, it -> - replacementData[index.toString()] = FirmFormatters.formatCommas(it, 1) - } - stats.statNumbers.forEach { (t, u) -> - replacementData[t] = FirmFormatters.formatCommas(u, 1) - } - } - - private fun injectReplacementDataForPets(replacementData: MutableMap<String, String>) { - val petData = this.petData ?: return - val petInfo = RepoManager.neuRepo.constants.petNumbers[petData.petId]?.get(petData.rarity) ?: return - if (petData.isStub) { - val mapLow = mutableMapOf<String, String>() - injectReplacementDataForPetLevel(petInfo, petInfo.lowLevel, mapLow) - val mapHigh = mutableMapOf<String, String>() - injectReplacementDataForPetLevel(petInfo, petInfo.highLevel, mapHigh) - mapHigh.forEach { (key, highValue) -> - mapLow.merge(key, highValue) { a, b -> "$a → $b" } - } - replacementData.putAll(mapLow) - replacementData["LVL"] = "${petInfo.lowLevel} → ${petInfo.highLevel}" - } else { - injectReplacementDataForPetLevel(petInfo, petData.levelData.currentLevel, replacementData) - replacementData["LVL"] = petData.levelData.currentLevel.toString() - } - } - - - private var itemStack_: ItemStack? = null - - private val itemStack: ItemStack - get() { - val itemStack = itemStack_ ?: run { - if (skyblockId == SkyblockId.COINS) - return@run ItemCache.coinItem(stackSize).also { it.appendLore(extraLore) } - val replacementData = mutableMapOf<String, String>() - injectReplacementDataForPets(replacementData) - return@run neuItem.asItemStack(idHint = skyblockId, replacementData) - .copyWithCount(stackSize) - .also { it.appendLore(extraLore) } - .also { enhanceStatsByStars(it, stars) } - } - if (itemStack_ == null) - itemStack_ = itemStack - return itemStack - } - - - private fun starString(stars: Int): Text { - if (stars <= 0) return Text.empty() - val tiers = listOf( - LegacyFormattingCode.GOLD, - LegacyFormattingCode.LIGHT_PURPLE, - LegacyFormattingCode.AQUA, - ) - val maxStars = 5 - if (stars > tiers.size * maxStars) return Text.literal(" ${stars}✪").withColor(Formatting.RED) - val starBaseTier = (stars - 1) / maxStars - val starBaseColor = tiers[starBaseTier] - val starsInCurrentTier = stars - starBaseTier * maxStars - val starString = Text.literal(" " + "✪".repeat(starsInCurrentTier)).withColor(starBaseColor.modern) - if (starBaseTier > 0) { - val starLastTier = tiers[starBaseTier - 1] - val starsInLastTier = 5 - starsInCurrentTier - starString.append(Text.literal("✪".repeat(starsInLastTier)).withColor(starLastTier.modern)) - } - return starString - } - - private fun enhanceStatsByStars(itemStack: ItemStack, stars: Int) { - if (stars == 0) return - // TODO: increase stats and add the star level into the nbt data so star displays work - itemStack.displayNameAccordingToNbt = itemStack.displayNameAccordingToNbt.copy() - .append(starString(stars)) - } - - fun asImmutableItemStack(): ItemStack { - return itemStack - } - - fun asItemStack(): ItemStack { - return itemStack.copy() - } -} - -object SBItemEntryDefinition : EntryDefinition<SBItemStack> { - override fun equals(o1: SBItemStack, o2: SBItemStack, context: ComparisonContext): Boolean { - return o1.skyblockId == o2.skyblockId && o1.getStackSize() == o2.getStackSize() - } - - override fun cheatsAs(entry: EntryStack<SBItemStack>?, value: SBItemStack): ItemStack { - return value.asItemStack() - } - - override fun getValueType(): Class<SBItemStack> = SBItemStack::class.java - override fun getType(): EntryType<SBItemStack> = EntryType.deferred(FirmamentReiPlugin.SKYBLOCK_ITEM_TYPE_ID) - - override fun getRenderer(): EntryRenderer<SBItemStack> = NEUItemEntryRenderer - - override fun getSerializer(): EntrySerializer<SBItemStack> { - return NEUItemEntrySerializer - } - - override fun getTagsFor(entry: EntryStack<SBItemStack>?, value: SBItemStack?): Stream<out TagKey<*>>? { - return Stream.empty() - } - - override fun asFormattedText(entry: EntryStack<SBItemStack>, value: SBItemStack): Text { - return VanillaEntryTypes.ITEM.definition.asFormattedText(entry.asItemEntry(), value.asItemStack()) - } - - override fun hash(entry: EntryStack<SBItemStack>, value: SBItemStack, context: ComparisonContext): Long { - // Repo items are immutable, and get replaced entirely when loaded from disk - return value.skyblockId.hashCode() * 31L - } - - override fun wildcard(entry: EntryStack<SBItemStack>?, value: SBItemStack): SBItemStack { - return value.copy(stackSize = 1, petData = RepoManager.getPotentialStubPetData(value.skyblockId), - stars = 0, extraLore = listOf()) - } - - override fun normalize(entry: EntryStack<SBItemStack>?, value: SBItemStack): SBItemStack { - return wildcard(entry, value) - } - - override fun copy(entry: EntryStack<SBItemStack>?, value: SBItemStack): SBItemStack { - return value - } - - override fun isEmpty(entry: EntryStack<SBItemStack>?, value: SBItemStack): Boolean { - return value.getStackSize() == 0 - } - - override fun getIdentifier(entry: EntryStack<SBItemStack>?, value: SBItemStack): Identifier { - return value.skyblockId.identifier - } - - fun getEntry(sbItemStack: SBItemStack): EntryStack<SBItemStack> = - EntryStack.of(this, sbItemStack) - - fun getEntry(skyblockId: SkyblockId, count: Int = 1): EntryStack<SBItemStack> = - getEntry(SBItemStack(skyblockId, count)) - - fun getEntry(ingredient: NEUIngredient): EntryStack<SBItemStack> = - getEntry(SkyblockId(ingredient.itemId), count = ingredient.amount.toInt()) - - fun getEntry(stack: ItemStack): EntryStack<SBItemStack> = - getEntry( - SBItemStack( - stack.skyBlockId ?: SkyblockId.NULL, - RepoManager.getNEUItem(stack.skyBlockId ?: SkyblockId.NULL), - stack.count, - petData = stack.petData?.let { PetData.fromHypixel(it) } - ) - ) -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/SkyblockCraftingRecipeDynamicGenerator.kt b/src/main/kotlin/moe/nea/firmament/rei/SkyblockCraftingRecipeDynamicGenerator.kt deleted file mode 100644 index 5136902..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/SkyblockCraftingRecipeDynamicGenerator.kt +++ /dev/null @@ -1,64 +0,0 @@ - - -package moe.nea.firmament.rei - -import io.github.moulberry.repo.data.NEUCraftingRecipe -import io.github.moulberry.repo.data.NEUForgeRecipe -import io.github.moulberry.repo.data.NEUKatUpgradeRecipe -import io.github.moulberry.repo.data.NEUMobDropRecipe -import io.github.moulberry.repo.data.NEURecipe -import java.util.Optional -import me.shedaniel.rei.api.client.registry.display.DynamicDisplayGenerator -import me.shedaniel.rei.api.client.view.ViewSearchBuilder -import me.shedaniel.rei.api.common.display.Display -import me.shedaniel.rei.api.common.entry.EntryStack -import moe.nea.firmament.rei.recipes.SBCraftingRecipe -import moe.nea.firmament.rei.recipes.SBEssenceUpgradeRecipe -import moe.nea.firmament.rei.recipes.SBForgeRecipe -import moe.nea.firmament.rei.recipes.SBKatRecipe -import moe.nea.firmament.rei.recipes.SBMobDropRecipe -import moe.nea.firmament.repo.EssenceRecipeProvider -import moe.nea.firmament.repo.RepoManager - - -val SkyblockCraftingRecipeDynamicGenerator = - neuDisplayGenerator<SBCraftingRecipe, NEUCraftingRecipe> { SBCraftingRecipe(it) } - -val SkyblockForgeRecipeDynamicGenerator = - neuDisplayGenerator<SBForgeRecipe, NEUForgeRecipe> { SBForgeRecipe(it) } - -val SkyblockMobDropRecipeDynamicGenerator = - neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> { SBMobDropRecipe(it) } - -val SkyblockKatRecipeDynamicGenerator = - neuDisplayGenerator<SBKatRecipe, NEUKatUpgradeRecipe> { SBKatRecipe(it) } -val SkyblockEssenceRecipeDynamicGenerator = - neuDisplayGenerator<SBEssenceUpgradeRecipe, EssenceRecipeProvider.EssenceUpgradeRecipe> { SBEssenceUpgradeRecipe(it) } - -inline fun <D : Display, reified T : NEURecipe> neuDisplayGenerator(crossinline mapper: (T) -> D) = - object : DynamicDisplayGenerator<D> { - override fun getRecipeFor(entry: EntryStack<*>): Optional<List<D>> { - if (entry.type != SBItemEntryDefinition.type) return Optional.empty() - val item = entry.castValue<SBItemStack>() - val recipes = RepoManager.getRecipesFor(item.skyblockId) - val craftingRecipes = recipes.filterIsInstance<T>() - return Optional.of(craftingRecipes.map(mapper)) - } - - override fun generate(builder: ViewSearchBuilder): Optional<List<D>> { - if (SBCraftingRecipe.Category.catIdentifier !in builder.categories) return Optional.empty() - return Optional.of( - RepoManager.getAllRecipes().filterIsInstance<T>().map { mapper(it) } - .toList() - ) - } - - override fun getUsageFor(entry: EntryStack<*>): Optional<List<D>> { - if (entry.type != SBItemEntryDefinition.type) return Optional.empty() - val item = entry.castValue<SBItemStack>() - val recipes = RepoManager.getUsagesFor(item.skyblockId) - val craftingRecipes = recipes.filterIsInstance<T>() - return Optional.of(craftingRecipes.map(mapper)) - - } - } diff --git a/src/main/kotlin/moe/nea/firmament/rei/SkyblockItemIdFocusedStackProvider.kt b/src/main/kotlin/moe/nea/firmament/rei/SkyblockItemIdFocusedStackProvider.kt deleted file mode 100644 index bb0a5a5..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/SkyblockItemIdFocusedStackProvider.kt +++ /dev/null @@ -1,25 +0,0 @@ - - -package moe.nea.firmament.rei - -import dev.architectury.event.CompoundEventResult -import me.shedaniel.math.Point -import me.shedaniel.rei.api.client.registry.screen.FocusedStackProvider -import me.shedaniel.rei.api.common.entry.EntryStack -import net.minecraft.client.gui.screen.Screen -import net.minecraft.client.gui.screen.ingame.HandledScreen -import moe.nea.firmament.mixins.accessor.AccessorHandledScreen -import moe.nea.firmament.util.skyBlockId - -object SkyblockItemIdFocusedStackProvider : FocusedStackProvider { - override fun provide(screen: Screen?, mouse: Point?): CompoundEventResult<EntryStack<*>> { - if (screen !is HandledScreen<*>) return CompoundEventResult.pass() - screen as AccessorHandledScreen - val focusedSlot = screen.focusedSlot_Firmament ?: return CompoundEventResult.pass() - val item = focusedSlot.stack ?: return CompoundEventResult.pass() - val skyblockId = item.skyBlockId ?: return CompoundEventResult.pass() - return CompoundEventResult.interruptTrue(SBItemEntryDefinition.getEntry(skyblockId)) - } - - override fun getPriority(): Double = 1_000_000.0 -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/math.kt b/src/main/kotlin/moe/nea/firmament/rei/math.kt deleted file mode 100644 index 1318beb..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/math.kt +++ /dev/null @@ -1,10 +0,0 @@ - - -package moe.nea.firmament.rei - -import me.shedaniel.math.Point - -operator fun Point.plus(other: Point): Point = Point( - this.x + other.x, - this.y + other.y, -) diff --git a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBCraftingRecipe.kt b/src/main/kotlin/moe/nea/firmament/rei/recipes/SBCraftingRecipe.kt deleted file mode 100644 index d6bbf0c..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBCraftingRecipe.kt +++ /dev/null @@ -1,55 +0,0 @@ - - -package moe.nea.firmament.rei.recipes - -import io.github.moulberry.repo.data.NEUCraftingRecipe -import io.github.moulberry.repo.data.NEUIngredient -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import me.shedaniel.rei.api.client.gui.Renderer -import me.shedaniel.rei.api.client.gui.widgets.Widget -import me.shedaniel.rei.api.client.gui.widgets.Widgets -import me.shedaniel.rei.api.client.registry.display.DisplayCategory -import me.shedaniel.rei.api.common.category.CategoryIdentifier -import me.shedaniel.rei.api.common.util.EntryStacks -import net.minecraft.block.Blocks -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.rei.SBItemEntryDefinition - -class SBCraftingRecipe(override val neuRecipe: NEUCraftingRecipe) : SBRecipe() { - override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.catIdentifier - - object Category : DisplayCategory<SBCraftingRecipe> { - val catIdentifier = CategoryIdentifier.of<SBCraftingRecipe>(Firmament.MOD_ID, "crafing_recipe") - override fun getCategoryIdentifier(): CategoryIdentifier<out SBCraftingRecipe> = catIdentifier - - override fun getTitle(): Text = Text.literal("SkyBlock Crafting") - - override fun getIcon(): Renderer = EntryStacks.of(Blocks.CRAFTING_TABLE) - override fun setupDisplay(display: SBCraftingRecipe, bounds: Rectangle): List<Widget> { - val point = Point(bounds.centerX - 58, bounds.centerY - 27) - return buildList { - add(Widgets.createRecipeBase(bounds)) - add(Widgets.createArrow(Point(point.x + 60, point.y + 18))) - add(Widgets.createResultSlotBackground(Point(point.x + 95, point.y + 19))) - for (i in 0 until 3) { - for (j in 0 until 3) { - val slot = Widgets.createSlot(Point(point.x + 1 + i * 18, point.y + 1 + j * 18)).markInput() - add(slot) - val item = display.neuRecipe.inputs[i + j * 3] - if (item == NEUIngredient.SENTINEL_EMPTY) continue - slot.entry(SBItemEntryDefinition.getEntry(item)) // TODO: make use of stackable item entries - } - } - add( - Widgets.createSlot(Point(point.x + 95, point.y + 19)) - .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.output)) - .disableBackground().markOutput() - ) - } - } - - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBEssenceUpgradeRecipe.kt b/src/main/kotlin/moe/nea/firmament/rei/recipes/SBEssenceUpgradeRecipe.kt deleted file mode 100644 index 80bc2b7..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBEssenceUpgradeRecipe.kt +++ /dev/null @@ -1,62 +0,0 @@ - -package moe.nea.firmament.rei.recipes - -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import me.shedaniel.rei.api.client.gui.Renderer -import me.shedaniel.rei.api.client.gui.widgets.Widget -import me.shedaniel.rei.api.client.gui.widgets.Widgets -import me.shedaniel.rei.api.client.registry.display.DisplayCategory -import me.shedaniel.rei.api.common.category.CategoryIdentifier -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.rei.SBItemEntryDefinition -import moe.nea.firmament.rei.SBItemStack -import moe.nea.firmament.repo.EssenceRecipeProvider -import moe.nea.firmament.util.SkyblockId - -class SBEssenceUpgradeRecipe(override val neuRecipe: EssenceRecipeProvider.EssenceUpgradeRecipe) : SBRecipe() { - object Category : DisplayCategory<SBEssenceUpgradeRecipe> { - override fun getCategoryIdentifier(): CategoryIdentifier<SBEssenceUpgradeRecipe> = - CategoryIdentifier.of(Firmament.MOD_ID, "essence_upgrade") - - override fun getTitle(): Text { - return Text.literal("Essence Upgrades") - } - - override fun getIcon(): Renderer { - return SBItemEntryDefinition.getEntry(SkyblockId("ESSENCE_WITHER")) - } - - override fun setupDisplay(display: SBEssenceUpgradeRecipe, bounds: Rectangle): List<Widget> { - val recipe = display.neuRecipe - val list = mutableListOf<Widget>() - list.add(Widgets.createRecipeBase(bounds)) - list.add(Widgets.createSlot(Point(bounds.minX + 12, bounds.centerY - 8 - 18 / 2)) - .markInput() - .entry(SBItemEntryDefinition.getEntry(SBItemStack(recipe.itemId).copy(stars = recipe.starCountAfter - 1)))) - list.add(Widgets.createSlot(Point(bounds.minX + 12, bounds.centerY - 8 + 18 / 2)) - .markInput() - .entry(SBItemEntryDefinition.getEntry(recipe.essenceIngredient))) - list.add(Widgets.createSlot(Point(bounds.maxX - 12 - 16, bounds.centerY - 8)) - .markOutput() - .entry(SBItemEntryDefinition.getEntry(SBItemStack(recipe.itemId).copy(stars = recipe.starCountAfter)))) - val extraItems = recipe.extraItems - list.add(Widgets.createArrow(Point(bounds.centerX - 24 / 2, - if (extraItems.isEmpty()) bounds.centerY - 17 / 2 - else bounds.centerY + 18 / 2))) - for ((index, item) in extraItems.withIndex()) { - list.add(Widgets.createSlot( - Point(bounds.centerX - extraItems.size * 16 / 2 - 2 / 2 + index * 18, - bounds.centerY - 18 / 2)) - .markInput() - .entry(SBItemEntryDefinition.getEntry(item))) - } - return list - } - } - - override fun getCategoryIdentifier(): CategoryIdentifier<*> { - return Category.categoryIdentifier - } -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBForgeRecipe.kt b/src/main/kotlin/moe/nea/firmament/rei/recipes/SBForgeRecipe.kt deleted file mode 100644 index 569f4a0..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBForgeRecipe.kt +++ /dev/null @@ -1,71 +0,0 @@ - - -package moe.nea.firmament.rei.recipes - -import io.github.moulberry.repo.data.NEUForgeRecipe -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import me.shedaniel.rei.api.client.gui.Renderer -import me.shedaniel.rei.api.client.gui.widgets.Widget -import me.shedaniel.rei.api.client.gui.widgets.Widgets -import me.shedaniel.rei.api.client.registry.display.DisplayCategory -import me.shedaniel.rei.api.common.category.CategoryIdentifier -import me.shedaniel.rei.api.common.util.EntryStacks -import kotlin.math.cos -import kotlin.math.sin -import kotlin.time.Duration.Companion.seconds -import net.minecraft.block.Blocks -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.rei.SBItemEntryDefinition -import moe.nea.firmament.rei.plus - -class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() { - override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier - - object Category : DisplayCategory<SBForgeRecipe> { - override fun getCategoryIdentifier(): CategoryIdentifier<SBForgeRecipe> = - CategoryIdentifier.of(Firmament.MOD_ID, "forge_recipe") - - override fun getTitle(): Text = Text.literal("Forge Recipes") - override fun getDisplayHeight(): Int { - return 104 - } - - override fun getIcon(): Renderer = EntryStacks.of(Blocks.ANVIL) - override fun setupDisplay(display: SBForgeRecipe, bounds: Rectangle): List<Widget> { - return buildList { - add(Widgets.createRecipeBase(bounds)) - add(Widgets.createResultSlotBackground(Point(bounds.minX + 124, bounds.minY + 46))) - val arrow = Widgets.createArrow(Point(bounds.minX + 90, bounds.minY + 54 - 18 / 2)) - add(arrow) - add(Widgets.createTooltip(arrow.bounds, Text.stringifiedTranslatable("firmament.recipe.forge.time", display.neuRecipe.duration.seconds))) - val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8) - val count = display.neuRecipe.inputs.size - if (count == 1) { - add( - Widgets.createSlot(Point(ingredientsCenter.x, ingredientsCenter.y)).markInput() - .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.inputs.single())) - ) - } else { - display.neuRecipe.inputs.forEachIndexed { idx, ingredient -> - val rad = Math.PI * 2 * idx / count - add( - Widgets.createSlot( - Point( - cos(rad) * 30, - sin(rad) * 30, - ) + ingredientsCenter - ).markInput().entry(SBItemEntryDefinition.getEntry(ingredient)) - ) - } - } - add( - Widgets.createSlot(Point(bounds.minX + 124, bounds.minY + 46)).markOutput().disableBackground() - .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.outputStack)) - ) - } - } - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBKatRecipe.kt b/src/main/kotlin/moe/nea/firmament/rei/recipes/SBKatRecipe.kt deleted file mode 100644 index f906a43..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBKatRecipe.kt +++ /dev/null @@ -1,224 +0,0 @@ - -package moe.nea.firmament.rei.recipes - -import io.github.moulberry.repo.data.NEUKatUpgradeRecipe -import io.github.notenoughupdates.moulconfig.common.IMinecraft -import io.github.notenoughupdates.moulconfig.gui.GuiComponent -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext -import io.github.notenoughupdates.moulconfig.gui.MouseEvent -import io.github.notenoughupdates.moulconfig.gui.component.SliderComponent -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import io.github.notenoughupdates.moulconfig.observer.Property -import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import me.shedaniel.rei.api.client.gui.Renderer -import me.shedaniel.rei.api.client.gui.widgets.Widget -import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds -import me.shedaniel.rei.api.client.gui.widgets.Widgets -import me.shedaniel.rei.api.client.registry.display.DisplayCategory -import me.shedaniel.rei.api.common.category.CategoryIdentifier -import me.shedaniel.rei.api.common.util.EntryStacks -import kotlin.time.Duration.Companion.seconds -import net.minecraft.block.Blocks -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.Element -import net.minecraft.item.Items -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.rei.PetData -import moe.nea.firmament.rei.SBItemEntryDefinition -import moe.nea.firmament.rei.SBItemStack -import moe.nea.firmament.util.FirmFormatters -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SkyblockId - -class SBKatRecipe(override val neuRecipe: NEUKatUpgradeRecipe) : SBRecipe() { - override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier - - object Category : DisplayCategory<SBKatRecipe> { - override fun getCategoryIdentifier(): CategoryIdentifier<SBKatRecipe> = - CategoryIdentifier.of(Firmament.MOD_ID, "kat_recipe") - - override fun getTitle(): Text = Text.literal("Kat Pet Upgrade") - override fun getDisplayHeight(): Int { - return 100 - } - - override fun getIcon(): Renderer = EntryStacks.of(Items.BONE) - override fun setupDisplay(display: SBKatRecipe, bounds: Rectangle): List<Widget> { - return buildList { - val arrowWidth = 24 - val recipe = display.neuRecipe - val levelValue = Property.upgrade(GetSetter.floating(0F)) - val slider = SliderComponent(levelValue, 1F, 100F, 1f, 100) - val outputStack = SBItemStack(SkyblockId(recipe.output.itemId)) - val inputStack = SBItemStack(SkyblockId(recipe.input.itemId)) - val inputLevelLabelCenter = Point(bounds.minX + 30 - 18 + 5 + 8, bounds.minY + 25) - val inputLevelLabel = Widgets.createLabel( - inputLevelLabelCenter, - Text.literal("")).centered() - val outputLevelLabelCenter = Point(bounds.maxX - 30 + 8, bounds.minY + 25) - val outputLevelLabel = Widgets.createLabel( - outputLevelLabelCenter, - Text.literal("")).centered() - val coinStack = SBItemStack(SkyblockId.COINS, recipe.coins.toInt()) - levelValue.whenChanged { oldValue, newValue -> - if (oldValue.toInt() == newValue.toInt()) return@whenChanged - val oldInput = inputStack.getPetData() ?: return@whenChanged - val newInput = PetData.forLevel(oldInput.petId, oldInput.rarity, newValue.toInt()) - inputStack.setPetData(newInput) - val oldOutput = outputStack.getPetData() ?: return@whenChanged - val newOutput = PetData(oldOutput.rarity, oldOutput.petId, newInput.exp) - outputStack.setPetData(newOutput) - inputLevelLabel.message = Text.literal(newInput.levelData.currentLevel.toString()) - inputLevelLabel.bounds.location = Point( - inputLevelLabelCenter.x - MC.font.getWidth(inputLevelLabel.message) / 2, - inputLevelLabelCenter.y) - outputLevelLabel.message = Text.literal(newOutput.levelData.currentLevel.toString()) - outputLevelLabel.bounds.location = Point( - outputLevelLabelCenter.x - MC.font.getWidth(outputLevelLabel.message) / 2, - outputLevelLabelCenter.y) - coinStack.setStackSize((recipe.coins * (1 - 0.3 * newValue / 100)).toInt()) - } - levelValue.set(1F) - add(Widgets.createRecipeBase(bounds)) - add(wrapWidget(Rectangle(bounds.centerX - slider.width / 2, - bounds.maxY - 30, - slider.width, - slider.height), - slider)) - add(Widgets.withTooltip( - Widgets.createArrow(Point(bounds.centerX - arrowWidth / 2, bounds.minY + 40)), - Text.literal("Upgrade time: " + FirmFormatters.formatTimespan(recipe.seconds.seconds)))) - - add(Widgets.createResultSlotBackground(Point(bounds.maxX - 30, bounds.minY + 40))) - add(inputLevelLabel) - add(outputLevelLabel) - add(Widgets.createSlot(Point(bounds.maxX - 30, bounds.minY + 40)).markOutput().disableBackground() - .entry(SBItemEntryDefinition.getEntry(outputStack))) - add(Widgets.createSlot(Point(bounds.minX + 30 - 18 + 5, bounds.minY + 40)).markInput() - .entry(SBItemEntryDefinition.getEntry(inputStack))) - - val allInputs = recipe.items.map { SBItemEntryDefinition.getEntry(it) } + - listOf(SBItemEntryDefinition.getEntry(coinStack)) - for ((index, item) in allInputs.withIndex()) { - add(Widgets.createSlot( - Point(bounds.centerX + index * 20 - allInputs.size * 18 / 2 - (allInputs.size - 1) * 2 / 2, - bounds.minY + 20)) - .markInput() - .entry(item)) - } - } - } - } -} - -fun wrapWidget(bounds: Rectangle, component: GuiComponent): Widget { - return object : WidgetWithBounds() { - override fun getBounds(): Rectangle { - return bounds - } - - override fun children(): List<Element> { - return listOf() - } - - override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - context.matrices.push() - context.matrices.translate(bounds.minX.toFloat(), bounds.minY.toFloat(), 0F) - component.render( - GuiImmediateContext( - ModernRenderContext(context), - bounds.minX, bounds.minY, - bounds.width, bounds.height, - mouseX - bounds.minX, mouseY - bounds.minY, - mouseX, mouseY, - mouseX.toFloat(), mouseY.toFloat() - )) - context.matrices.pop() - } - - override fun mouseMoved(mouseX: Double, mouseY: Double) { - val mouseXInt = mouseX.toInt() - val mouseYInt = mouseY.toInt() - component.mouseEvent(MouseEvent.Move(0F, 0F), - GuiImmediateContext( - IMinecraft.instance.provideTopLevelRenderContext(), - bounds.minX, bounds.minY, - bounds.width, bounds.height, - mouseXInt - bounds.minX, mouseYInt - bounds.minY, - mouseXInt, mouseYInt, - mouseX.toFloat(), mouseY.toFloat() - )) - } - - override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { - val mouseXInt = mouseX.toInt() - val mouseYInt = mouseY.toInt() - return component.mouseEvent(MouseEvent.Click(button, true), - GuiImmediateContext( - IMinecraft.instance.provideTopLevelRenderContext(), - bounds.minX, bounds.minY, - bounds.width, bounds.height, - mouseXInt - bounds.minX, mouseYInt - bounds.minY, - mouseXInt, mouseYInt, - mouseX.toFloat(), mouseY.toFloat() - )) - } - - override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { - val mouseXInt = mouseX.toInt() - val mouseYInt = mouseY.toInt() - return component.mouseEvent(MouseEvent.Click(button, false), - GuiImmediateContext( - IMinecraft.instance.provideTopLevelRenderContext(), - bounds.minX, bounds.minY, - bounds.width, bounds.height, - mouseXInt - bounds.minX, mouseYInt - bounds.minY, - mouseXInt, mouseYInt, - mouseX.toFloat(), mouseY.toFloat() - )) - } - - override fun mouseDragged( - mouseX: Double, - mouseY: Double, - button: Int, - deltaX: Double, - deltaY: Double - ): Boolean { - val mouseXInt = mouseX.toInt() - val mouseYInt = mouseY.toInt() - return component.mouseEvent(MouseEvent.Move(deltaX.toFloat(), deltaY.toFloat()), - GuiImmediateContext( - IMinecraft.instance.provideTopLevelRenderContext(), - bounds.minX, bounds.minY, - bounds.width, bounds.height, - mouseXInt - bounds.minX, mouseYInt - bounds.minY, - mouseXInt, mouseYInt, - mouseX.toFloat(), mouseY.toFloat() - )) - - } - - override fun mouseScrolled( - mouseX: Double, - mouseY: Double, - horizontalAmount: Double, - verticalAmount: Double - ): Boolean { - val mouseXInt = mouseX.toInt() - val mouseYInt = mouseY.toInt() - return component.mouseEvent(MouseEvent.Scroll(verticalAmount.toFloat()), - GuiImmediateContext( - IMinecraft.instance.provideTopLevelRenderContext(), - bounds.minX, bounds.minY, - bounds.width, bounds.height, - mouseXInt - bounds.minX, mouseYInt - bounds.minY, - mouseXInt, mouseYInt, - mouseX.toFloat(), mouseY.toFloat() - )) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBMobDropRecipe.kt b/src/main/kotlin/moe/nea/firmament/rei/recipes/SBMobDropRecipe.kt deleted file mode 100644 index a02220f..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBMobDropRecipe.kt +++ /dev/null @@ -1,108 +0,0 @@ - -package moe.nea.firmament.rei.recipes - -import io.github.moulberry.repo.data.NEUMobDropRecipe -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import me.shedaniel.rei.api.client.gui.Renderer -import me.shedaniel.rei.api.client.gui.widgets.Widget -import me.shedaniel.rei.api.client.gui.widgets.Widgets -import me.shedaniel.rei.api.client.registry.display.DisplayCategory -import me.shedaniel.rei.api.common.category.CategoryIdentifier -import me.shedaniel.rei.api.common.util.EntryStacks -import net.minecraft.item.Items -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import moe.nea.firmament.Firmament -import moe.nea.firmament.gui.entity.EntityRenderer -import moe.nea.firmament.gui.entity.EntityWidget -import moe.nea.firmament.rei.SBItemEntryDefinition - -class SBMobDropRecipe(override val neuRecipe: NEUMobDropRecipe) : SBRecipe() { - override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier - - object Category : DisplayCategory<SBMobDropRecipe> { - override fun getCategoryIdentifier(): CategoryIdentifier<SBMobDropRecipe> = - CategoryIdentifier.of(Firmament.MOD_ID, "mob_drop_recipe") - - override fun getTitle(): Text = Text.literal("Mob Drops") - override fun getDisplayHeight(): Int { - return 100 - } - - override fun getIcon(): Renderer = EntryStacks.of(Items.DIAMOND_SWORD) - override fun setupDisplay(display: SBMobDropRecipe, bounds: Rectangle): List<Widget> { - return buildList { - add(Widgets.createRecipeBase(bounds)) - val source = display.neuRecipe.render - val entity = if (source.startsWith("@")) { - EntityRenderer.constructEntity(Identifier.of(source.substring(1))) - } else { - EntityRenderer.applyModifiers(source, listOf()) - } - if (entity != null) { - val level = display.neuRecipe.level - val fullMobName = - if (level > 0) Text.translatable("firmament.recipe.mobs.name", level, display.neuRecipe.name) - else Text.translatable("firmament.recipe.mobs.name.nolevel", display.neuRecipe.name) - val tt = mutableListOf<Text>() - tt.add((fullMobName)) - tt.add(Text.literal("")) - if (display.neuRecipe.coins > 0) { - tt.add(Text.stringifiedTranslatable("firmament.recipe.mobs.coins", display.neuRecipe.coins)) - } - if (display.neuRecipe.combatExperience > 0) { - tt.add( - Text.stringifiedTranslatable( - "firmament.recipe.mobs.combat", - display.neuRecipe.combatExperience - ) - ) - } - if (display.neuRecipe.enchantingExperience > 0) { - tt.add( - Text.stringifiedTranslatable( - "firmament.recipe.mobs.exp", - display.neuRecipe.enchantingExperience - ) - ) - } - if (display.neuRecipe.extra != null) - display.neuRecipe.extra.mapTo(tt) { Text.literal(it) } - if (tt.size == 2) - tt.removeAt(1) - add( - Widgets.withTooltip( - EntityWidget(entity, Point(bounds.minX + 5, bounds.minY + 15)), - tt - ) - ) - } - add( - Widgets.createLabel(Point(bounds.minX + 15, bounds.minY + 5), Text.literal(display.neuRecipe.name)) - .leftAligned() - ) - var x = bounds.minX + 60 - var y = bounds.minY + 20 - for (drop in display.neuRecipe.drops) { - val lore = drop.extra.mapTo(mutableListOf()) { Text.literal(it) } - if (drop.chance != null) { - lore += listOf(Text.translatable("firmament.recipe.mobs.drops", drop.chance)) - } - val item = SBItemEntryDefinition.getEntry(drop.dropItem) - .value.copy(extraLore = lore) - add( - Widgets.createSlot(Point(x, y)).markOutput() - .entries(listOf(SBItemEntryDefinition.getEntry(item))) - ) - x += 18 - if (x > bounds.maxX - 30) { - x = bounds.minX + 60 - y += 18 - } - } - } - } - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBRecipe.kt b/src/main/kotlin/moe/nea/firmament/rei/recipes/SBRecipe.kt deleted file mode 100644 index 7872d83..0000000 --- a/src/main/kotlin/moe/nea/firmament/rei/recipes/SBRecipe.kt +++ /dev/null @@ -1,31 +0,0 @@ - - -package moe.nea.firmament.rei.recipes - -import io.github.moulberry.repo.data.NEUIngredient -import io.github.moulberry.repo.data.NEURecipe -import me.shedaniel.rei.api.common.display.Display -import me.shedaniel.rei.api.common.entry.EntryIngredient -import moe.nea.firmament.rei.SBItemEntryDefinition -import moe.nea.firmament.util.SkyblockId - -abstract class SBRecipe : Display { - abstract val neuRecipe: NEURecipe - override fun getInputEntries(): List<EntryIngredient> { - return neuRecipe.allInputs - .filter { it.itemId != NEUIngredient.NEU_SENTINEL_EMPTY } - .map { - val entryStack = SBItemEntryDefinition.getEntry(SkyblockId(it.itemId)) - EntryIngredient.of(entryStack) - } - } - - override fun getOutputEntries(): List<EntryIngredient> { - return neuRecipe.allOutputs - .filter { it.itemId != NEUIngredient.NEU_SENTINEL_EMPTY } - .map { - val entryStack = SBItemEntryDefinition.getEntry(SkyblockId(it.itemId)) - EntryIngredient.of(entryStack) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt b/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt deleted file mode 100644 index 91a6b50..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/BetterRepoRecipeCache.kt +++ /dev/null @@ -1,28 +0,0 @@ - -package moe.nea.firmament.repo - -import io.github.moulberry.repo.IReloadable -import io.github.moulberry.repo.NEURepository -import io.github.moulberry.repo.data.NEURecipe -import moe.nea.firmament.util.SkyblockId - -class BetterRepoRecipeCache(val essenceRecipeProvider: EssenceRecipeProvider) : IReloadable { - var usages: Map<SkyblockId, Set<NEURecipe>> = mapOf() - var recipes: Map<SkyblockId, Set<NEURecipe>> = mapOf() - - override fun reload(repository: NEURepository) { - val usages = mutableMapOf<SkyblockId, MutableSet<NEURecipe>>() - val recipes = mutableMapOf<SkyblockId, MutableSet<NEURecipe>>() - val baseRecipes = repository.items.items.values - .asSequence() - .flatMap { it.recipes } - val extraRecipes = essenceRecipeProvider.recipes - (baseRecipes + extraRecipes) - .forEach { recipe -> - recipe.allInputs.forEach { usages.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) } - recipe.allOutputs.forEach { recipes.getOrPut(SkyblockId(it.itemId), ::mutableSetOf).add(recipe) } - } - this.usages = usages - this.recipes = recipes - } -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt b/src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt deleted file mode 100644 index 1833258..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/EssenceRecipeProvider.kt +++ /dev/null @@ -1,50 +0,0 @@ - -package moe.nea.firmament.repo - -import io.github.moulberry.repo.IReloadable -import io.github.moulberry.repo.NEURepository -import io.github.moulberry.repo.data.NEUIngredient -import io.github.moulberry.repo.data.NEURecipe -import moe.nea.firmament.util.SkyblockId - -class EssenceRecipeProvider : IReloadable { - data class EssenceUpgradeRecipe( - val itemId: SkyblockId, - val starCountAfter: Int, - val essenceCost: Int, - val essenceType: String, // TODO: replace with proper type - val extraItems: List<NEUIngredient>, - ) : NEURecipe { - val essenceIngredient= NEUIngredient.fromString("${essenceType}:$essenceCost") - val allUpgradeComponents = listOf(essenceIngredient) + extraItems - - override fun getAllInputs(): Collection<NEUIngredient> { - return listOf(NEUIngredient.fromString(itemId.neuItem + ":1")) + allUpgradeComponents - } - - override fun getAllOutputs(): Collection<NEUIngredient> { - return listOf(NEUIngredient.fromString(itemId.neuItem + ":1")) - } - } - - var recipes = listOf<EssenceUpgradeRecipe>() - private set - - override fun reload(repository: NEURepository) { - val recipes = mutableListOf<EssenceUpgradeRecipe>() - for ((neuId, costs) in repository.constants.essenceCost.costs) { - // TODO: add dungeonization costs. this is in repo, but not in the repo parser. - for ((starCountAfter, essenceCost) in costs.essenceCosts.entries) { - val items = costs.itemCosts[starCountAfter] ?: emptyList() - recipes.add( - EssenceUpgradeRecipe( - SkyblockId(neuId), - starCountAfter, - essenceCost, - "ESSENCE_" + costs.type.uppercase(), // how flimsy - items.map { NEUIngredient.fromString(it) })) - } - } - this.recipes = recipes - } -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt b/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt deleted file mode 100644 index fbc9eb8..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/ExpLadder.kt +++ /dev/null @@ -1,94 +0,0 @@ - - -package moe.nea.firmament.repo - -import com.google.common.cache.CacheBuilder -import com.google.common.cache.CacheLoader -import io.github.moulberry.repo.IReloadable -import io.github.moulberry.repo.NEURepository -import io.github.moulberry.repo.constants.PetLevelingBehaviourOverride -import io.github.moulberry.repo.data.Rarity - -object ExpLadders : IReloadable { - - data class PetLevel( - val currentLevel: Int, - val maxLevel: Int, - val expRequiredForNextLevel: Long, - val expRequiredForMaxLevel: Long, - val expInCurrentLevel: Float, - var expTotal: Float, - ) { - val percentageToNextLevel: Float = expInCurrentLevel / expRequiredForNextLevel - } - - data class ExpLadder( - val individualLevelCost: List<Long>, - ) { - val cumulativeLevelCost = individualLevelCost.runningFold(0F) { a, b -> a + b }.map { it.toLong() } - fun getPetLevel(currentExp: Double): PetLevel { - val currentOneIndexedLevel = cumulativeLevelCost.indexOfLast { it <= currentExp } + 1 - val expForNextLevel = if (currentOneIndexedLevel > individualLevelCost.size) { // Max leveled pet - individualLevelCost.last() - } else { - individualLevelCost[currentOneIndexedLevel - 1] - } - val expInCurrentLevel = - if (currentOneIndexedLevel >= cumulativeLevelCost.size) - currentExp.toFloat() - cumulativeLevelCost.last() - else - (expForNextLevel - (cumulativeLevelCost[currentOneIndexedLevel] - currentExp.toFloat())).coerceAtLeast( - 0F - ) - return PetLevel( - currentLevel = currentOneIndexedLevel, - maxLevel = cumulativeLevelCost.size, - expRequiredForNextLevel = expForNextLevel, - expRequiredForMaxLevel = cumulativeLevelCost.last(), - expInCurrentLevel = expInCurrentLevel, - expTotal = currentExp.toFloat() - ) - } - - fun getPetExpForLevel(level: Int): Long { - if (level < 2) return 0L - if (level >= cumulativeLevelCost.size) return cumulativeLevelCost.last() - return cumulativeLevelCost[level - 1] - } - } - - private data class Key(val petIdWithoutRarity: String, val rarity: Rarity) - - private val expLadders = CacheBuilder.newBuilder() - .build(object : CacheLoader<Key, ExpLadder>() { - override fun load(key: Key): ExpLadder { - val pld = RepoManager.neuRepo.constants.petLevelingData - var exp = pld.petExpCostForLevel - var offset = pld.petLevelStartOffset[key.rarity]!! - var maxLevel = 100 - val override = pld.petLevelingBehaviourOverrides[key.petIdWithoutRarity] - if (override != null) { - maxLevel = override.maxLevel ?: maxLevel - offset = override.petLevelStartOffset?.get(key.rarity) ?: offset - when (override.petExpCostModifierType) { - PetLevelingBehaviourOverride.PetExpModifierType.APPEND -> - exp = exp + override.petExpCostModifier - - PetLevelingBehaviourOverride.PetExpModifierType.REPLACE -> - exp = override.petExpCostModifier - - null -> {} - } - } - return ExpLadder(exp.drop(offset).take(maxLevel - 1).map { it.toLong() }) - } - }) - - override fun reload(repository: NEURepository?) { - expLadders.invalidateAll() - } - - fun getExpLadder(petId: String, rarity: Rarity): ExpLadder { - return expLadders.get(Key(petId, rarity)) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/HypixelStaticData.kt b/src/main/kotlin/moe/nea/firmament/repo/HypixelStaticData.kt deleted file mode 100644 index 5c2a2fc..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/HypixelStaticData.kt +++ /dev/null @@ -1,107 +0,0 @@ - - -package moe.nea.firmament.repo - -import io.ktor.client.call.body -import io.ktor.client.request.get -import org.apache.logging.log4j.LogManager -import org.lwjgl.glfw.GLFW -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.withTimeoutOrNull -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlin.time.Duration.Companion.minutes -import moe.nea.firmament.Firmament -import moe.nea.firmament.apis.CollectionResponse -import moe.nea.firmament.apis.CollectionSkillData -import moe.nea.firmament.keybindings.IKeyBinding -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.async.waitForInput - -object HypixelStaticData { - private val logger = LogManager.getLogger("Firmament.HypixelStaticData") - private val moulberryBaseUrl = "https://moulberry.codes" - private val hypixelApiBaseUrl = "https://api.hypixel.net" - var lowestBin: Map<SkyblockId, Double> = mapOf() - private set - var bazaarData: Map<SkyblockId, BazaarData> = mapOf() - private set - var collectionData: Map<String, CollectionSkillData> = mapOf() - private set - - @Serializable - data class BazaarData( - @SerialName("product_id") - val productId: SkyblockId.BazaarStock, - @SerialName("quick_status") - val quickStatus: BazaarStatus, - ) - - @Serializable - data class BazaarStatus( - val sellPrice: Double, - val sellVolume: Long, - val sellMovingWeek: Long, - val sellOrders: Long, - val buyPrice: Double, - val buyVolume: Long, - val buyMovingWeek: Long, - val buyOrders: Long - ) - - @Serializable - private data class BazaarResponse( - val success: Boolean, - val products: Map<SkyblockId.BazaarStock, BazaarData> = mapOf(), - ) - - fun getPriceOfItem(item: SkyblockId): Double? = bazaarData[item]?.quickStatus?.buyPrice ?: lowestBin[item] - - - fun spawnDataCollectionLoop() { - Firmament.coroutineScope.launch { - logger.info("Updating collection data") - updateCollectionData() - } - Firmament.coroutineScope.launch { - while (true) { - logger.info("Updating NEU prices") - updatePrices() - withTimeoutOrNull(10.minutes) { waitForInput(IKeyBinding.ofKeyCode(GLFW.GLFW_KEY_U)) } - } - } - } - - private suspend fun updatePrices() { - awaitAll( - Firmament.coroutineScope.async { fetchBazaarPrices() }, - Firmament.coroutineScope.async { fetchPricesFromMoulberry() }, - ) - } - - private suspend fun fetchPricesFromMoulberry() { - lowestBin = Firmament.httpClient.get("$moulberryBaseUrl/lowestbin.json") - .body<Map<SkyblockId, Double>>() - } - - private suspend fun fetchBazaarPrices() { - val response = Firmament.httpClient.get("$hypixelApiBaseUrl/skyblock/bazaar").body<BazaarResponse>() - if (!response.success) { - logger.warn("Retrieved unsuccessful bazaar data") - } - bazaarData = response.products.mapKeys { it.key.toRepoId() } - } - - private suspend fun updateCollectionData() { - val response = - Firmament.httpClient.get("$hypixelApiBaseUrl/resources/skyblock/collections").body<CollectionResponse>() - if (!response.success) { - logger.warn("Retrieved unsuccessful collection data") - } - collectionData = response.collections - logger.info("Downloaded ${collectionData.values.sumOf { it.items.values.size }} collections") - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt b/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt deleted file mode 100644 index 08143be..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/ItemCache.kt +++ /dev/null @@ -1,215 +0,0 @@ - - -package moe.nea.firmament.repo - -import com.mojang.serialization.Dynamic -import io.github.moulberry.repo.IReloadable -import io.github.moulberry.repo.NEURepository -import io.github.moulberry.repo.data.NEUItem -import io.github.notenoughupdates.moulconfig.xml.Bind -import java.text.NumberFormat -import java.util.UUID -import java.util.concurrent.ConcurrentHashMap -import org.apache.logging.log4j.LogManager -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch -import kotlin.jvm.optionals.getOrNull -import net.minecraft.SharedConstants -import net.minecraft.client.resource.language.I18n -import net.minecraft.component.DataComponentTypes -import net.minecraft.component.type.NbtComponent -import net.minecraft.datafixer.Schemas -import net.minecraft.datafixer.TypeReferences -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import net.minecraft.nbt.NbtCompound -import net.minecraft.nbt.NbtElement -import net.minecraft.nbt.NbtOps -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.gui.config.HudMeta -import moe.nea.firmament.gui.config.HudPosition -import moe.nea.firmament.gui.hud.MoulConfigHud -import moe.nea.firmament.util.LegacyTagParser -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.appendLore -import moe.nea.firmament.util.item.setCustomName -import moe.nea.firmament.util.item.setSkullOwner -import moe.nea.firmament.util.modifyLore -import moe.nea.firmament.util.skyblockId - -object ItemCache : IReloadable { - private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap() - private val df = Schemas.getFixer() - val logger = LogManager.getLogger("${Firmament.logger.name}.ItemCache") - var isFlawless = true - private set - - private fun NEUItem.get10809CompoundTag(): NbtCompound = NbtCompound().apply { - put("tag", LegacyTagParser.parse(nbttag)) - putString("id", minecraftItemId) - putByte("Count", 1) - putShort("Damage", damage.toShort()) - } - - private fun NbtCompound.transformFrom10809ToModern(): NbtCompound? = - try { - df.update( - TypeReferences.ITEM_STACK, - Dynamic(NbtOps.INSTANCE, this), - -1, - SharedConstants.getGameVersion().saveVersion.id - ).value as NbtCompound - } catch (e: Exception) { - isFlawless = false - logger.error("Could not data fix up $this", e) - null - } - - fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack { - return ItemStack(Items.PAINTING).apply { - setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null")) - appendLore( - listOf( - Text.stringifiedTranslatable( - "firmament.repo.brokenitem", - (neuItem?.skyblockItemId ?: idHint) - ) - ) - ) - } - } - - private fun NEUItem.asItemStackNow(): ItemStack { - try { - val oldItemTag = get10809CompoundTag() - val modernItemTag = oldItemTag.transformFrom10809ToModern() - ?: return brokenItemStack(this) - val itemInstance = - ItemStack.fromNbt(MC.defaultRegistries, modernItemTag).getOrNull() ?: return brokenItemStack(this) - val extraAttributes = oldItemTag.getCompound("tag").getCompound("ExtraAttributes") - if (extraAttributes != null) - itemInstance.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(extraAttributes)) - return itemInstance - } catch (e: Exception) { - e.printStackTrace() - return brokenItemStack(this) - } - } - - fun NEUItem?.asItemStack(idHint: SkyblockId? = null, loreReplacements: Map<String, String>? = null): ItemStack { - if (this == null) return brokenItemStack(null, idHint) - var s = cache[this.skyblockItemId] - if (s == null) { - s = asItemStackNow() - cache[this.skyblockItemId] = s - } - if (!loreReplacements.isNullOrEmpty()) { - s = s.copy()!! - s.applyLoreReplacements(loreReplacements) - s.setCustomName(s.name.applyLoreReplacements(loreReplacements)) - } - return s - } - - fun ItemStack.applyLoreReplacements(loreReplacements: Map<String, String>) { - modifyLore { lore -> - lore.map { - it.applyLoreReplacements(loreReplacements) - } - } - } - - fun Text.applyLoreReplacements(loreReplacements: Map<String, String>): Text { - assert(this.siblings.isEmpty()) - var string = this.string - loreReplacements.forEach { (find, replace) -> - string = string.replace("{$find}", replace) - } - return Text.literal(string).styled { this.style } - } - - fun NEUItem.getIdentifier() = skyblockId.identifier - - var job: Job? = null - object ReloadProgressHud : MoulConfigHud( - "repo_reload", HudMeta(HudPosition(0.0, 0.0, 1F), Text.literal("Repo Reload"), 180, 18)) { - - - var isEnabled = false - override fun shouldRender(): Boolean { - return isEnabled - } - - @get:Bind("current") - var current: Double = 0.0 - - @get:Bind("label") - var label: String = "" - - @get:Bind("max") - var max: Double = 0.0 - - fun reportProgress(label: String, current: Int, max: Int) { - this.label = label - this.current = current.toDouble() - this.max = max.toDouble() - } - } - - override fun reload(repository: NEURepository) { - val j = job - if (j != null && j.isActive) { - j.cancel() - } - cache.clear() - isFlawless = true - - job = Firmament.coroutineScope.launch { - val items = repository.items?.items - if (items == null) { - ReloadProgressHud.isEnabled = false - return@launch - } - val recacheItems = I18n.translate("firmament.repo.cache") - ReloadProgressHud.reportProgress(recacheItems, 0, items.size) - ReloadProgressHud.isEnabled = true - var i = 0 - items.values.forEach { - it.asItemStack() // Rebuild cache - ReloadProgressHud.reportProgress(recacheItems, i++, items.size) - } - ReloadProgressHud.isEnabled = false - } - } - - fun coinItem(coinAmount: Int): ItemStack { - var uuid = UUID.fromString("2070f6cb-f5db-367a-acd0-64d39a7e5d1b") - var texture = - "http://textures.minecraft.net/texture/538071721cc5b4cd406ce431a13f86083a8973e1064d2f8897869930ee6e5237" - if (coinAmount >= 100000) { - uuid = UUID.fromString("94fa2455-2881-31fe-bb4e-e3e24d58dbe3") - texture = - "http://textures.minecraft.net/texture/c9b77999fed3a2758bfeaf0793e52283817bea64044bf43ef29433f954bb52f6" - } - if (coinAmount >= 10000000) { - uuid = UUID.fromString("0af8df1f-098c-3b72-ac6b-65d65fd0b668") - texture = - "http://textures.minecraft.net/texture/7b951fed6a7b2cbc2036916dec7a46c4a56481564d14f945b6ebc03382766d3b" - } - val itemStack = ItemStack(Items.PLAYER_HEAD) - itemStack.setCustomName(Text.literal("§r§6" + NumberFormat.getInstance().format(coinAmount) + " Coins")) - itemStack.setSkullOwner(uuid, texture) - return itemStack - } -} - - -operator fun NbtCompound.set(key: String, value: String) { - putString(key, value) -} - -operator fun NbtCompound.set(key: String, value: NbtElement) { - put(key, value) -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt b/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt deleted file mode 100644 index 770de85..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/ItemNameLookup.kt +++ /dev/null @@ -1,98 +0,0 @@ - -package moe.nea.firmament.repo - -import io.github.moulberry.repo.IReloadable -import io.github.moulberry.repo.NEURepository -import io.github.moulberry.repo.data.NEUItem -import java.util.NavigableMap -import java.util.TreeMap -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.removeColorCodes -import moe.nea.firmament.util.skyblockId - -object ItemNameLookup : IReloadable { - - fun getItemNameChunks(name: String): Set<String> { - return name.removeColorCodes().split(" ").filterTo(mutableSetOf()) { it.isNotBlank() } - } - - var nameMap: NavigableMap<String, out Set<SkyblockId>> = TreeMap() - - override fun reload(repository: NEURepository) { - val nameMap = TreeMap<String, MutableSet<SkyblockId>>() - repository.items.items.values.forEach { item -> - getAllNamesForItem(item).forEach { name -> - val chunks = getItemNameChunks(name) - chunks.forEach { chunk -> - val set = nameMap.getOrPut(chunk, ::mutableSetOf) - set.add(item.skyblockId) - } - } - } - this.nameMap = nameMap - } - - fun getAllNamesForItem(item: NEUItem): Set<String> { - val names = mutableSetOf<String>() - names.add(item.displayName) - if (item.displayName.contains("Enchanted Book")) { - val enchantName = item.lore.firstOrNull() - if (enchantName != null) { - names.add(enchantName) - } - } - return names - } - - fun findItemCandidatesByName(name: String): MutableSet<SkyblockId> { - val candidates = mutableSetOf<SkyblockId>() - for (chunk in getItemNameChunks(name)) { - val set = nameMap[chunk] ?: emptySet() - candidates.addAll(set) - } - return candidates - } - - - fun guessItemByName( - /** - * The display name of the item. Color codes will be ignored. - */ - name: String, - /** - * Whether the [name] may contain other text, such as reforges, master stars and such. - */ - mayBeMangled: Boolean - ): SkyblockId? { - val cleanName = name.removeColorCodes() - return findBestItemFromCandidates( - findItemCandidatesByName(cleanName), - cleanName, - true - ) - } - - fun findBestItemFromCandidates( - candidates: Iterable<SkyblockId>, - name: String, mayBeMangled: Boolean - ): SkyblockId? { - val expectedClean = name.removeColorCodes() - var bestMatch: SkyblockId? = null - var bestMatchLength = -1 - for (candidate in candidates) { - val item = RepoManager.getNEUItem(candidate) ?: continue - for (name in getAllNamesForItem(item)) { - val actualClean = name.removeColorCodes() - val matches = if (mayBeMangled) expectedClean == actualClean - else expectedClean.contains(actualClean) - if (!matches) continue - if (actualClean.length > bestMatchLength) { - bestMatch = candidate - bestMatchLength = actualClean.length - } - } - } - return bestMatch - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt deleted file mode 100644 index d674f23..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoDownloadManager.kt +++ /dev/null @@ -1,128 +0,0 @@ - - -package moe.nea.firmament.repo - -import io.ktor.client.call.body -import io.ktor.client.request.get -import io.ktor.client.statement.bodyAsChannel -import io.ktor.utils.io.jvm.nio.copyTo -import java.io.IOException -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardOpenOption -import java.util.zip.ZipInputStream -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.withContext -import kotlinx.serialization.Serializable -import kotlin.io.path.createDirectories -import kotlin.io.path.exists -import kotlin.io.path.inputStream -import kotlin.io.path.outputStream -import kotlin.io.path.readText -import kotlin.io.path.writeText -import moe.nea.firmament.Firmament -import moe.nea.firmament.Firmament.logger -import moe.nea.firmament.util.iterate - - -object RepoDownloadManager { - - val repoSavedLocation = Firmament.DATA_DIR.resolve("repo-extracted") - val repoMetadataLocation = Firmament.DATA_DIR.resolve("loaded-repo-sha.txt") - - private fun loadSavedVersionHash(): String? = - if (repoSavedLocation.exists()) { - if (repoMetadataLocation.exists()) { - try { - repoMetadataLocation.readText().trim() - } catch (e: IOException) { - null - } - } else { - null - } - } else null - - private fun saveVersionHash(versionHash: String) { - latestSavedVersionHash = versionHash - repoMetadataLocation.writeText(versionHash) - } - - var latestSavedVersionHash: String? = loadSavedVersionHash() - private set - - @Serializable - private class GithubCommitsResponse(val sha: String) - - private suspend fun requestLatestGithubSha(): String? { - if (RepoManager.Config.branch == "prerelease") { - RepoManager.Config.branch = "master" - } - val response = - Firmament.httpClient.get("https://api.github.com/repos/${RepoManager.Config.username}/${RepoManager.Config.reponame}/commits/${RepoManager.Config.branch}") - if (response.status.value != 200) { - return null - } - return response.body<GithubCommitsResponse>().sha - } - - private suspend fun downloadGithubArchive(url: String): Path = withContext(IO) { - val response = Firmament.httpClient.get(url) - val targetFile = Files.createTempFile("firmament-repo", ".zip") - val outputChannel = Files.newByteChannel(targetFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE) - response.bodyAsChannel().copyTo(outputChannel) - targetFile - } - - /** - * Downloads the latest repository from github, setting [latestSavedVersionHash]. - * @return true, if an update was performed, false, otherwise (no update needed, or wasn't able to complete update) - */ - suspend fun downloadUpdate(force: Boolean): Boolean = withContext(CoroutineName("Repo Update Check")) { - val latestSha = requestLatestGithubSha() - if (latestSha == null) { - logger.warn("Could not request github API to retrieve latest REPO sha.") - return@withContext false - } - val currentSha = loadSavedVersionHash() - if (latestSha != currentSha || force) { - val requestUrl = - "https://github.com/${RepoManager.Config.username}/${RepoManager.Config.reponame}/archive/$latestSha.zip" - logger.info("Planning to upgrade repository from $currentSha to $latestSha from $requestUrl") - val zipFile = downloadGithubArchive(requestUrl) - logger.info("Download repository zip file to $zipFile. Deleting old repository") - withContext(IO) { repoSavedLocation.toFile().deleteRecursively() } - logger.info("Extracting new repository") - withContext(IO) { extractNewRepository(zipFile) } - logger.info("Repository loaded on disk.") - saveVersionHash(latestSha) - return@withContext true - } else { - logger.debug("Repository on latest sha $currentSha. Not performing update") - return@withContext false - } - } - - private fun extractNewRepository(zipFile: Path) { - repoSavedLocation.createDirectories() - ZipInputStream(zipFile.inputStream()).use { cis -> - while (true) { - val entry = cis.nextEntry ?: break - if (entry.isDirectory) continue - val extractedLocation = - repoSavedLocation.resolve( - entry.name.substringAfter('/', missingDelimiterValue = "") - ) - if (repoSavedLocation !in extractedLocation.iterate { it.parent }) { - logger.error("Firmament detected an invalid zip file. This is a potential security risk, please report this in the Firmament discord.") - throw RuntimeException("Firmament detected an invalid zip file. This is a potential security risk, please report this in the Firmament discord.") - } - extractedLocation.parent.createDirectories() - extractedLocation.outputStream().use { cis.copyTo(it) } - } - } - } - - -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt deleted file mode 100644 index f0da397..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoManager.kt +++ /dev/null @@ -1,145 +0,0 @@ -package moe.nea.firmament.repo - -import io.github.moulberry.repo.NEURepository -import io.github.moulberry.repo.NEURepositoryException -import io.github.moulberry.repo.data.NEUItem -import io.github.moulberry.repo.data.NEURecipe -import io.github.moulberry.repo.data.Rarity -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents -import kotlinx.coroutines.launch -import net.minecraft.client.MinecraftClient -import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.Firmament.logger -import moe.nea.firmament.events.ReloadRegistrationEvent -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.rei.PetData -import moe.nea.firmament.util.MinecraftDispatcher -import moe.nea.firmament.util.SkyblockId - -object RepoManager { - object Config : ManagedConfig("repo") { - var username by string("username") { "NotEnoughUpdates" } - var reponame by string("reponame") { "NotEnoughUpdates-REPO" } - var branch by string("branch") { "master" } - val autoUpdate by toggle("autoUpdate") { true } - val reset by button("reset") { - username = "NotEnoughUpdates" - reponame = "NotEnoughUpdates-REPO" - branch = "master" - save() - } - - val disableItemGroups by toggle("disable-item-groups") { true } - val reload by button("reload") { - save() - RepoManager.reload() - } - val redownload by button("redownload") { - save() - RepoManager.launchAsyncUpdate(true) - } - } - - val currentDownloadedSha by RepoDownloadManager::latestSavedVersionHash - - var recentlyFailedToUpdateItemList = false - - val neuRepo: NEURepository = NEURepository.of(RepoDownloadManager.repoSavedLocation).apply { - registerReloadListener(ItemCache) - registerReloadListener(ExpLadders) - registerReloadListener(ItemNameLookup) - ReloadRegistrationEvent.publish(ReloadRegistrationEvent(this)) - registerReloadListener { - Firmament.coroutineScope.launch(MinecraftDispatcher) { - if (!trySendClientboundUpdateRecipesPacket()) { - logger.warn("Failed to issue a ClientboundUpdateRecipesPacket (to reload REI). This may lead to an outdated item list.") - recentlyFailedToUpdateItemList = true - } - } - } - } - - val essenceRecipeProvider = EssenceRecipeProvider() - val recipeCache = BetterRepoRecipeCache(essenceRecipeProvider) - - init { - neuRepo.registerReloadListener(essenceRecipeProvider) - neuRepo.registerReloadListener(recipeCache) - } - - fun getAllRecipes() = neuRepo.items.items.values.asSequence().flatMap { it.recipes } - - fun getRecipesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.recipes[skyblockId] ?: setOf() - fun getUsagesFor(skyblockId: SkyblockId): Set<NEURecipe> = recipeCache.usages[skyblockId] ?: setOf() - - private fun trySendClientboundUpdateRecipesPacket(): Boolean { - return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes( - SynchronizeRecipesS2CPacket(mutableListOf()) - ) != null - } - - init { - ClientTickEvents.START_WORLD_TICK.register(ClientTickEvents.StartWorldTick { - if (recentlyFailedToUpdateItemList && trySendClientboundUpdateRecipesPacket()) - recentlyFailedToUpdateItemList = false - }) - } - - fun getNEUItem(skyblockId: SkyblockId): NEUItem? = neuRepo.items.getItemBySkyblockId(skyblockId.neuItem) - - fun launchAsyncUpdate(force: Boolean = false) { - Firmament.coroutineScope.launch { - ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper boundy bar - ItemCache.ReloadProgressHud.isEnabled = true - try { - RepoDownloadManager.downloadUpdate(force) - ItemCache.ReloadProgressHud.reportProgress("Download complete", 1, 1) - } finally { - ItemCache.ReloadProgressHud.isEnabled = false - } - reload() - } - } - - fun reload() { - try { - ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk", - 0, - -1) // TODO: replace with a proper boundy bar - ItemCache.ReloadProgressHud.isEnabled = true - neuRepo.reload() - } catch (exc: NEURepositoryException) { - MinecraftClient.getInstance().player?.sendMessage( - Text.literal("Failed to reload repository. This will result in some mod features not working.") - ) - ItemCache.ReloadProgressHud.isEnabled = false - exc.printStackTrace() - } - } - - fun initialize() { - if (Config.autoUpdate) { - launchAsyncUpdate() - } else { - reload() - } - } - - fun getPotentialStubPetData(skyblockId: SkyblockId): PetData? { - val parts = skyblockId.neuItem.split(";") - if (parts.size != 2) { - return null - } - val (petId, rarityIndex) = parts - if (!rarityIndex.all { it.isDigit() }) { - return null - } - val intIndex = rarityIndex.toInt() - if (intIndex !in Rarity.values().indices) return null - if (petId !in neuRepo.constants.petNumbers) return null - return PetData(Rarity.values()[intIndex], petId, 0.0, true) - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt b/src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt deleted file mode 100644 index f92fe4f..0000000 --- a/src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt +++ /dev/null @@ -1,126 +0,0 @@ - -package moe.nea.firmament.repo - -import java.io.InputStream -import java.nio.file.Files -import java.nio.file.Path -import java.util.* -import net.fabricmc.fabric.api.resource.ModResourcePack -import net.fabricmc.loader.api.FabricLoader -import net.fabricmc.loader.api.metadata.ModMetadata -import kotlin.io.path.exists -import kotlin.io.path.isRegularFile -import kotlin.io.path.relativeTo -import kotlin.streams.asSequence -import net.minecraft.resource.AbstractFileResourcePack -import net.minecraft.resource.InputSupplier -import net.minecraft.resource.NamespaceResourceManager -import net.minecraft.resource.Resource -import net.minecraft.resource.ResourcePack -import net.minecraft.resource.ResourcePackInfo -import net.minecraft.resource.ResourcePackSource -import net.minecraft.resource.ResourceType -import net.minecraft.resource.metadata.ResourceMetadata -import net.minecraft.resource.metadata.ResourceMetadataReader -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import net.minecraft.util.PathUtil -import moe.nea.firmament.Firmament - -class RepoModResourcePack(val basePath: Path) : ModResourcePack { - companion object { - fun append(packs: MutableList<in ModResourcePack>) { - Firmament.logger.info("Registering mod resource pack") - packs.add(RepoModResourcePack(RepoDownloadManager.repoSavedLocation)) - } - - fun createResourceDirectly(identifier: Identifier): Optional<Resource> { - val pack = RepoModResourcePack(RepoDownloadManager.repoSavedLocation) - return Optional.of( - Resource( - pack, - pack.open(ResourceType.CLIENT_RESOURCES, identifier) ?: return Optional.empty() - ) { - val base = - pack.open(ResourceType.CLIENT_RESOURCES, identifier.withPath(identifier.path + ".mcmeta")) - if (base == null) - ResourceMetadata.NONE - else - NamespaceResourceManager.loadMetadata(base) - } - ) - } - } - - override fun close() { - } - - override fun openRoot(vararg segments: String): InputSupplier<InputStream>? { - return getFile(segments)?.let { InputSupplier.create(it) } - } - - fun getFile(segments: Array<out String>): Path? { - PathUtil.validatePath(*segments) - val path = segments.fold(basePath, Path::resolve) - if (!path.isRegularFile()) return null - return path - } - - override fun open(type: ResourceType?, id: Identifier): InputSupplier<InputStream>? { - if (type != ResourceType.CLIENT_RESOURCES) return null - if (id.namespace != "neurepo") return null - val file = getFile(id.path.split("/").toTypedArray()) - return file?.let { InputSupplier.create(it) } - } - - override fun findResources( - type: ResourceType?, - namespace: String, - prefix: String, - consumer: ResourcePack.ResultConsumer - ) { - if (namespace != "neurepo") return - if (type != ResourceType.CLIENT_RESOURCES) return - - val prefixPath = basePath.resolve(prefix) - if (!prefixPath.exists()) - return - Files.walk(prefixPath) - .asSequence() - .map { it.relativeTo(basePath) } - .forEach { - consumer.accept(Identifier.of("neurepo", it.toString()), InputSupplier.create(it)) - } - } - - override fun getNamespaces(type: ResourceType?): Set<String> { - if (type != ResourceType.CLIENT_RESOURCES) return emptySet() - return setOf("neurepo") - } - - override fun <T> parseMetadata(metaReader: ResourceMetadataReader<T>): T? { - return AbstractFileResourcePack.parseMetadata( - metaReader, """ -{ - "pack": { - "pack_format": 12, - "description": "NEU Repo Resources" - } -} -""".trimIndent().byteInputStream() - ) - } - - override fun getInfo(): ResourcePackInfo { - return ResourcePackInfo("neurepo", Text.literal("NEU Repo"), ResourcePackSource.BUILTIN, Optional.empty()) - } - - override fun getFabricModMetadata(): ModMetadata { - return FabricLoader.getInstance().getModContainer("firmament") - .get().metadata - } - - override fun createOverlay(overlay: String): ModResourcePack { - return RepoModResourcePack(basePath.resolve(overlay)) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/Base64Util.kt b/src/main/kotlin/moe/nea/firmament/util/Base64Util.kt deleted file mode 100644 index 44bcdfd..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/Base64Util.kt +++ /dev/null @@ -1,10 +0,0 @@ - -package moe.nea.firmament.util - -object Base64Util { - fun String.padToValidBase64(): String { - val align = this.length % 4 - if (align == 0) return this - return this + "=".repeat(4 - align) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/BazaarPriceStrategy.kt b/src/main/kotlin/moe/nea/firmament/util/BazaarPriceStrategy.kt deleted file mode 100644 index 002eedb..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/BazaarPriceStrategy.kt +++ /dev/null @@ -1,19 +0,0 @@ - -package moe.nea.firmament.util - -import moe.nea.firmament.repo.HypixelStaticData - -enum class BazaarPriceStrategy { - BUY_ORDER, - SELL_ORDER, - NPC_SELL; - - fun getSellPrice(skyblockId: SkyblockId): Double { - val bazaarEntry = HypixelStaticData.bazaarData[skyblockId] ?: return 0.0 - return when (this) { - BUY_ORDER -> bazaarEntry.quickStatus.sellPrice - SELL_ORDER -> bazaarEntry.quickStatus.buyPrice - NPC_SELL -> TODO() - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/ClipboardUtils.kt b/src/main/kotlin/moe/nea/firmament/util/ClipboardUtils.kt deleted file mode 100644 index 7b9b836..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/ClipboardUtils.kt +++ /dev/null @@ -1,24 +0,0 @@ - - -package moe.nea.firmament.util - -import moe.nea.firmament.Firmament - -object ClipboardUtils { - fun setTextContent(string: String) { - try { - MC.keyboard.clipboard = string.ifEmpty { " " } - } catch (e: Exception) { - Firmament.logger.error("Could not write clipboard", e) - } - } - - fun getTextContents(): String { - try { - return MC.keyboard.clipboard ?: "" - } catch (e: Exception) { - Firmament.logger.error("Could not read clipboard", e) - return "" - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/CommonSoundEffects.kt b/src/main/kotlin/moe/nea/firmament/util/CommonSoundEffects.kt deleted file mode 100644 index a97a2cb..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/CommonSoundEffects.kt +++ /dev/null @@ -1,26 +0,0 @@ - - -package moe.nea.firmament.util - -import net.minecraft.client.sound.PositionedSoundInstance -import net.minecraft.sound.SoundEvent -import net.minecraft.util.Identifier - -// TODO: Replace these with custom sound events that just re use the vanilla ogg s -object CommonSoundEffects { - fun playSound(identifier: Identifier) { - MC.soundManager.play(PositionedSoundInstance.master(SoundEvent.of(identifier), 1F)) - } - - fun playFailure() { - playSound(Identifier.of("minecraft", "block.anvil.place")) - } - - fun playSuccess() { - playDing() - } - - fun playDing() { - playSound(Identifier.of("minecraft", "entity.arrow.hit_player")) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/DurabilityBarEvent.kt b/src/main/kotlin/moe/nea/firmament/util/DurabilityBarEvent.kt deleted file mode 100644 index 993462c..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/DurabilityBarEvent.kt +++ /dev/null @@ -1,20 +0,0 @@ - -package moe.nea.firmament.util - -import me.shedaniel.math.Color -import net.minecraft.item.ItemStack -import moe.nea.firmament.events.FirmamentEvent -import moe.nea.firmament.events.FirmamentEventBus - -data class DurabilityBarEvent( - val item: ItemStack, -) : FirmamentEvent() { - data class DurabilityBar( - val color: Color, - val percentage: Float, - ) - - var barOverride: DurabilityBar? = null - - companion object : FirmamentEventBus<DurabilityBarEvent>() -} diff --git a/src/main/kotlin/moe/nea/firmament/util/ErrorBoundary.kt b/src/main/kotlin/moe/nea/firmament/util/ErrorBoundary.kt deleted file mode 100644 index fbc5b37..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/ErrorBoundary.kt +++ /dev/null @@ -1,10 +0,0 @@ - - -package moe.nea.firmament.util - - -fun <T> errorBoundary(block: () -> T): T? { - // TODO: implement a proper error boundary here to avoid crashing minecraft code - return block() -} - diff --git a/src/main/kotlin/moe/nea/firmament/util/FirmFormatters.kt b/src/main/kotlin/moe/nea/firmament/util/FirmFormatters.kt deleted file mode 100644 index c3bdd16..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/FirmFormatters.kt +++ /dev/null @@ -1,59 +0,0 @@ - - -package moe.nea.firmament.util - -import com.google.common.math.IntMath.pow -import kotlin.math.absoluteValue -import kotlin.time.Duration - -object FirmFormatters { - fun formatCommas(int: Int, segments: Int = 3): String = formatCommas(int.toLong(), segments) - fun formatCommas(long: Long, segments: Int = 3): String { - val α = long / 1000 - if (α != 0L) { - return formatCommas(α, segments) + "," + (long - α * 1000).toString().padStart(3, '0') - } - return long.toString() - } - - fun formatCommas(float: Float, fractionalDigits: Int): String = formatCommas(float.toDouble(), fractionalDigits) - fun formatCommas(double: Double, fractionalDigits: Int): String { - val long = double.toLong() - val δ = (double - long).absoluteValue - val μ = pow(10, fractionalDigits) - val digits = (μ * δ).toInt().toString().padStart(fractionalDigits, '0').trimEnd('0') - return formatCommas(long) + (if (digits.isEmpty()) "" else ".$digits") - } - - fun formatDistance(distance: Double): String { - if (distance < 10) - return "%.1fm".format(distance) - return "%dm".format(distance.toInt()) - } - - fun formatTimespan(duration: Duration, millis: Boolean = false): String { - if (duration.isInfinite()) { - return if (duration.isPositive()) "∞" - else "-∞" - } - val sb = StringBuilder() - if (duration.isNegative()) sb.append("-") - duration.toComponents { days, hours, minutes, seconds, nanoseconds -> - if (days > 0) { - sb.append(days).append("d") - } - if (hours > 0) { - sb.append(hours).append("h") - } - if (minutes > 0) { - sb.append(minutes).append("m") - } - sb.append(seconds).append("s") - if (millis) { - sb.append(nanoseconds / 1_000_000).append("ms") - } - } - return sb.toString() - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/FragmentGuiScreen.kt b/src/main/kotlin/moe/nea/firmament/util/FragmentGuiScreen.kt deleted file mode 100644 index 5e13d51..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/FragmentGuiScreen.kt +++ /dev/null @@ -1,93 +0,0 @@ - - -package moe.nea.firmament.util - -import io.github.notenoughupdates.moulconfig.gui.GuiContext -import me.shedaniel.math.Dimension -import me.shedaniel.math.Point -import me.shedaniel.math.Rectangle -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.gui.screen.Screen -import net.minecraft.text.Text - -abstract class FragmentGuiScreen( - val dismissOnOutOfBounds: Boolean = true -) : Screen(Text.literal("")) { - var popup: MoulConfigFragment? = null - - fun createPopup(context: GuiContext, position: Point) { - popup = MoulConfigFragment(context, position) { popup = null } - } - - override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - super.render(context, mouseX, mouseY, delta) - context.matrices.push() - context.matrices.translate(0f, 0f, 1000f) - popup?.render(context, mouseX, mouseY, delta) - context.matrices.pop() - } - - private inline fun ifPopup(ifYes: (MoulConfigFragment) -> Unit): Boolean { - val p = popup ?: return false - ifYes(p) - return true - } - - override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { - return ifPopup { - it.keyPressed(keyCode, scanCode, modifiers) - } - } - - override fun keyReleased(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { - return ifPopup { - it.keyReleased(keyCode, scanCode, modifiers) - } - } - - override fun mouseMoved(mouseX: Double, mouseY: Double) { - ifPopup { it.mouseMoved(mouseX, mouseY) } - } - - override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { - return ifPopup { - it.mouseReleased(mouseX, mouseY, button) - } - } - - override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean { - return ifPopup { - it.mouseDragged(mouseX, mouseY, button, deltaX, deltaY) - } - } - - override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { - return ifPopup { - if (!Rectangle( - it.position, - Dimension(it.context.root.width, it.context.root.height) - ).contains(Point(mouseX, mouseY)) - && dismissOnOutOfBounds - ) { - popup = null - } else { - it.mouseClicked(mouseX, mouseY, button) - } - }|| super.mouseClicked(mouseX, mouseY, button) - } - - override fun charTyped(chr: Char, modifiers: Int): Boolean { - return ifPopup { it.charTyped(chr, modifiers) } - } - - override fun mouseScrolled( - mouseX: Double, - mouseY: Double, - horizontalAmount: Double, - verticalAmount: Double - ): Boolean { - return ifPopup { - it.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/GetRectangle.kt b/src/main/kotlin/moe/nea/firmament/util/GetRectangle.kt deleted file mode 100644 index ec64f31..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/GetRectangle.kt +++ /dev/null @@ -1,17 +0,0 @@ - - -package moe.nea.firmament.util - -import me.shedaniel.math.Rectangle -import moe.nea.firmament.mixins.accessor.AccessorHandledScreen -import net.minecraft.client.gui.screen.ingame.HandledScreen - -fun HandledScreen<*>.getRectangle(): Rectangle { - this as AccessorHandledScreen - return Rectangle( - getX_Firmament(), - getY_Firmament(), - getBackgroundWidth_Firmament(), - getBackgroundHeight_Firmament() - ) -} diff --git a/src/main/kotlin/moe/nea/firmament/util/HoveredItemStack.kt b/src/main/kotlin/moe/nea/firmament/util/HoveredItemStack.kt deleted file mode 100644 index 47a59d0..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/HoveredItemStack.kt +++ /dev/null @@ -1,31 +0,0 @@ - - -package moe.nea.firmament.util - -import me.shedaniel.math.impl.PointHelper -import me.shedaniel.rei.api.client.REIRuntime -import me.shedaniel.rei.api.client.gui.widgets.Slot -import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry -import net.minecraft.client.gui.Element -import net.minecraft.client.gui.ParentElement -import net.minecraft.client.gui.screen.ingame.HandledScreen -import net.minecraft.item.ItemStack -import moe.nea.firmament.mixins.accessor.AccessorHandledScreen - - -val HandledScreen<*>.focusedItemStack: ItemStack? - get() { - this as AccessorHandledScreen - val vanillaSlot = this.focusedSlot_Firmament?.stack - if (vanillaSlot != null) return vanillaSlot - val focusedSlot = ScreenRegistry.getInstance().getFocusedStack(this, PointHelper.ofMouse()) - if (focusedSlot != null) return focusedSlot.cheatsAs().value - var baseElement: Element? = REIRuntime.getInstance().overlay.orElse(null) - val mx = PointHelper.getMouseFloatingX() - val my = PointHelper.getMouseFloatingY() - while (true) { - if (baseElement is Slot) return baseElement.currentEntry.cheatsAs().value - if (baseElement !is ParentElement) return null - baseElement = baseElement.hoveredElement(mx, my).orElse(null) - } - } diff --git a/src/main/kotlin/moe/nea/firmament/util/IdentifierSerializer.kt b/src/main/kotlin/moe/nea/firmament/util/IdentifierSerializer.kt deleted file mode 100644 index 65c5b1c..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/IdentifierSerializer.kt +++ /dev/null @@ -1,25 +0,0 @@ - -package moe.nea.firmament.util - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import net.minecraft.util.Identifier - -object IdentifierSerializer : KSerializer<Identifier> { - val delegateSerializer = String.serializer() - override val descriptor: SerialDescriptor - get() = PrimitiveSerialDescriptor("Identifier", PrimitiveKind.STRING) - - override fun deserialize(decoder: Decoder): Identifier { - return Identifier.of(decoder.decodeSerializableValue(delegateSerializer)) - } - - override fun serialize(encoder: Encoder, value: Identifier) { - encoder.encodeSerializableValue(delegateSerializer, value.toString()) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/IdentityCharacteristics.kt b/src/main/kotlin/moe/nea/firmament/util/IdentityCharacteristics.kt deleted file mode 100644 index f6054c4..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/IdentityCharacteristics.kt +++ /dev/null @@ -1,15 +0,0 @@ - - -package moe.nea.firmament.util - -class IdentityCharacteristics<T>(val value: T) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is IdentityCharacteristics<*>) return false - return value === other.value - } - - override fun hashCode(): Int { - return System.identityHashCode(value) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/ItemUtil.kt b/src/main/kotlin/moe/nea/firmament/util/ItemUtil.kt deleted file mode 100644 index 40d6198..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/ItemUtil.kt +++ /dev/null @@ -1,26 +0,0 @@ - - -package moe.nea.firmament.util - -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NbtCompound -import net.minecraft.nbt.NbtList -import net.minecraft.text.Text -import moe.nea.firmament.util.item.loreAccordingToNbt - - -fun ItemStack.appendLore(args: List<Text>) { - if (args.isEmpty()) return - modifyLore { - val loreList = loreAccordingToNbt.toMutableList() - for (arg in args) { - loreList.add(arg) - } - loreList - } -} - -fun ItemStack.modifyLore(update: (List<Text>) -> List<Text>) { - val loreList = loreAccordingToNbt - loreAccordingToNbt = update(loreList) -} diff --git a/src/main/kotlin/moe/nea/firmament/util/LegacyFormattingCode.kt b/src/main/kotlin/moe/nea/firmament/util/LegacyFormattingCode.kt deleted file mode 100644 index 44bacfc..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/LegacyFormattingCode.kt +++ /dev/null @@ -1,35 +0,0 @@ - - -package moe.nea.firmament.util - -import net.minecraft.util.Formatting - -enum class LegacyFormattingCode(val label: String, val char: Char, val index: Int) { - BLACK("BLACK", '0', 0), - DARK_BLUE("DARK_BLUE", '1', 1), - DARK_GREEN("DARK_GREEN", '2', 2), - DARK_AQUA("DARK_AQUA", '3', 3), - DARK_RED("DARK_RED", '4', 4), - DARK_PURPLE("DARK_PURPLE", '5', 5), - GOLD("GOLD", '6', 6), - GRAY("GRAY", '7', 7), - DARK_GRAY("DARK_GRAY", '8', 8), - BLUE("BLUE", '9', 9), - GREEN("GREEN", 'a', 10), - AQUA("AQUA", 'b', 11), - RED("RED", 'c', 12), - LIGHT_PURPLE("LIGHT_PURPLE", 'd', 13), - YELLOW("YELLOW", 'e', 14), - WHITE("WHITE", 'f', 15), - OBFUSCATED("OBFUSCATED", 'k', -1), - BOLD("BOLD", 'l', -1), - STRIKETHROUGH("STRIKETHROUGH", 'm', -1), - UNDERLINE("UNDERLINE", 'n', -1), - ITALIC("ITALIC", 'o', -1), - RESET("RESET", 'r', -1); - - val modern = Formatting.byCode(char)!! - - val formattingCode = "§$char" - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/LegacyTagParser.kt b/src/main/kotlin/moe/nea/firmament/util/LegacyTagParser.kt deleted file mode 100644 index 4e08da1..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/LegacyTagParser.kt +++ /dev/null @@ -1,245 +0,0 @@ - - -package moe.nea.firmament.util - -import java.util.* -import net.minecraft.nbt.AbstractNbtNumber -import net.minecraft.nbt.NbtByte -import net.minecraft.nbt.NbtCompound -import net.minecraft.nbt.NbtDouble -import net.minecraft.nbt.NbtElement -import net.minecraft.nbt.NbtFloat -import net.minecraft.nbt.NbtInt -import net.minecraft.nbt.NbtList -import net.minecraft.nbt.NbtLong -import net.minecraft.nbt.NbtShort -import net.minecraft.nbt.NbtString - -class LegacyTagParser private constructor(string: String) { - data class TagParsingException(val baseString: String, val offset: Int, val mes0: String) : - Exception("$mes0 at $offset in `$baseString`.") - - class StringRacer(val backing: String) { - var idx = 0 - val stack = Stack<Int>() - - fun pushState() { - stack.push(idx) - } - - fun popState() { - idx = stack.pop() - } - - fun discardState() { - stack.pop() - } - - fun peek(count: Int): String { - return backing.substring(minOf(idx, backing.length), minOf(idx + count, backing.length)) - } - - fun finished(): Boolean { - return peek(1).isEmpty() - } - - fun peekReq(count: Int): String? { - val p = peek(count) - if (p.length != count) - return null - return p - } - - fun consumeCountReq(count: Int): String? { - val p = peekReq(count) - if (p != null) - idx += count - return p - } - - fun tryConsume(string: String): Boolean { - val p = peek(string.length) - if (p != string) - return false - idx += p.length - return true - } - - fun consumeWhile(shouldConsumeThisString: (String) -> Boolean): String { - var lastString: String = "" - while (true) { - val nextString = lastString + peek(1) - if (!shouldConsumeThisString(nextString)) { - return lastString - } - idx++ - lastString = nextString - } - } - - fun expect(search: String, errorMessage: String) { - if (!tryConsume(search)) - error(errorMessage) - } - - fun error(errorMessage: String): Nothing { - throw TagParsingException(backing, idx, errorMessage) - } - - } - - val racer = StringRacer(string) - val baseTag = parseTag() - - companion object { - val digitRange = "0123456789-" - fun parse(string: String): NbtCompound { - return LegacyTagParser(string).baseTag - } - } - - fun skipWhitespace() { - racer.consumeWhile { Character.isWhitespace(it.last()) } // Only check last since other chars are always checked before. - } - - fun parseTag(): NbtCompound { - skipWhitespace() - racer.expect("{", "Expected '{’ at start of tag") - skipWhitespace() - val tag = NbtCompound() - while (!racer.tryConsume("}")) { - skipWhitespace() - val lhs = parseIdentifier() - skipWhitespace() - racer.expect(":", "Expected ':' after identifier in tag") - skipWhitespace() - val rhs = parseAny() - tag.put(lhs, rhs) - racer.tryConsume(",") - skipWhitespace() - } - return tag - } - - private fun parseAny(): NbtElement { - skipWhitespace() - val nextChar = racer.peekReq(1) ?: racer.error("Expected new object, found EOF") - return when { - nextChar == "{" -> parseTag() - nextChar == "[" -> parseList() - nextChar == "\"" -> parseStringTag() - nextChar.first() in (digitRange) -> parseNumericTag() - else -> racer.error("Unexpected token found. Expected start of new element") - } - } - - fun parseList(): NbtList { - skipWhitespace() - racer.expect("[", "Expected '[' at start of tag") - skipWhitespace() - val list = NbtList() - while (!racer.tryConsume("]")) { - skipWhitespace() - racer.pushState() - val lhs = racer.consumeWhile { it.all { it in digitRange } } - skipWhitespace() - if (!racer.tryConsume(":") || lhs.isEmpty()) { // No prefixed 0: - racer.popState() - list.add(parseAny()) // Reparse our number (or not a number) as actual tag - } else { - racer.discardState() - skipWhitespace() - list.add(parseAny()) // Ignore prefix indexes. They should not be generated out of order by any vanilla implementation (which is what NEU should export). Instead append where it appears in order. - } - skipWhitespace() - racer.tryConsume(",") - } - return list - } - - fun parseQuotedString(): String { - skipWhitespace() - racer.expect("\"", "Expected '\"' at string start") - val sb = StringBuilder() - while (true) { - when (val peek = racer.consumeCountReq(1)) { - "\"" -> break - "\\" -> { - val escaped = racer.consumeCountReq(1) ?: racer.error("Unfinished backslash escape") - if (escaped != "\"" && escaped != "\\") { - // Surprisingly i couldn't find unicode escapes to be generated by the original minecraft 1.8.9 implementation - racer.idx-- - racer.error("Invalid backslash escape '$escaped'") - } - sb.append(escaped) - } - - null -> racer.error("Unfinished string") - else -> { - sb.append(peek) - } - } - } - return sb.toString() - } - - fun parseStringTag(): NbtString { - return NbtString.of(parseQuotedString()) - } - - object Patterns { - val DOUBLE = "([-+]?[0-9]*\\.?[0-9]+)[d|D]".toRegex() - val FLOAT = "([-+]?[0-9]*\\.?[0-9]+)[f|F]".toRegex() - val BYTE = "([-+]?[0-9]+)[b|B]".toRegex() - val LONG = "([-+]?[0-9]+)[l|L]".toRegex() - val SHORT = "([-+]?[0-9]+)[s|S]".toRegex() - val INTEGER = "([-+]?[0-9]+)".toRegex() - val DOUBLE_UNTYPED = "([-+]?[0-9]*\\.?[0-9]+)".toRegex() - val ROUGH_PATTERN = "[-+]?[0-9]*\\.?[0-9]*[dDbBfFlLsS]?".toRegex() - } - - fun parseNumericTag(): AbstractNbtNumber { - skipWhitespace() - val textForm = racer.consumeWhile { Patterns.ROUGH_PATTERN.matchEntire(it) != null } - if (textForm.isEmpty()) { - racer.error("Expected numeric tag (starting with either -, +, . or a digit") - } - val floatMatch = Patterns.FLOAT.matchEntire(textForm) - if (floatMatch != null) { - return NbtFloat.of(floatMatch.groups[1]!!.value.toFloat()) - } - val byteMatch = Patterns.BYTE.matchEntire(textForm) - if (byteMatch != null) { - return NbtByte.of(byteMatch.groups[1]!!.value.toByte()) - } - val longMatch = Patterns.LONG.matchEntire(textForm) - if (longMatch != null) { - return NbtLong.of(longMatch.groups[1]!!.value.toLong()) - } - val shortMatch = Patterns.SHORT.matchEntire(textForm) - if (shortMatch != null) { - return NbtShort.of(shortMatch.groups[1]!!.value.toShort()) - } - val integerMatch = Patterns.INTEGER.matchEntire(textForm) - if (integerMatch != null) { - return NbtInt.of(integerMatch.groups[1]!!.value.toInt()) - } - val doubleMatch = Patterns.DOUBLE.matchEntire(textForm) ?: Patterns.DOUBLE_UNTYPED.matchEntire(textForm) - if (doubleMatch != null) { - return NbtDouble.of(doubleMatch.groups[1]!!.value.toDouble()) - } - throw IllegalStateException("Could not properly parse numeric tag '$textForm', despite passing rough verification. This is a bug in the LegacyTagParser") - } - - private fun parseIdentifier(): String { - skipWhitespace() - if (racer.peek(1) == "\"") { - return parseQuotedString() - } - return racer.consumeWhile { - val x = it.last() - x != ':' && !Character.isWhitespace(x) - } - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/LoadResource.kt b/src/main/kotlin/moe/nea/firmament/util/LoadResource.kt deleted file mode 100644 index 4bc8704..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/LoadResource.kt +++ /dev/null @@ -1,20 +0,0 @@ - -package moe.nea.firmament.util - -import java.io.InputStream -import kotlin.io.path.inputStream -import kotlin.jvm.optionals.getOrNull -import net.minecraft.util.Identifier -import moe.nea.firmament.repo.RepoDownloadManager - - -fun Identifier.openFirmamentResource(): InputStream { - val resource = MC.resourceManager.getResource(this).getOrNull() - if (resource == null) { - if (namespace == "neurepo") - return RepoDownloadManager.repoSavedLocation.resolve(path).inputStream() - error("Could not read resource $this") - } - return resource.inputStream -} - diff --git a/src/main/kotlin/moe/nea/firmament/util/Locraw.kt b/src/main/kotlin/moe/nea/firmament/util/Locraw.kt deleted file mode 100644 index 9778bc7..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/Locraw.kt +++ /dev/null @@ -1,12 +0,0 @@ - - -package moe.nea.firmament.util - -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient - -@Serializable -data class Locraw(val server: String, val gametype: String? = null, val mode: String? = null, val map: String? = null) { - @Transient - val skyblockLocation = if (gametype == "SKYBLOCK") mode?.let(SkyBlockIsland::forMode) else null -} diff --git a/src/main/kotlin/moe/nea/firmament/util/LogIfNull.kt b/src/main/kotlin/moe/nea/firmament/util/LogIfNull.kt deleted file mode 100644 index 600c5e6..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/LogIfNull.kt +++ /dev/null @@ -1,8 +0,0 @@ - -package moe.nea.firmament.util - - -fun runNull(block: () -> Unit): Nothing? { - block() - return null -} diff --git a/src/main/kotlin/moe/nea/firmament/util/MC.kt b/src/main/kotlin/moe/nea/firmament/util/MC.kt deleted file mode 100644 index b0d3056..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/MC.kt +++ /dev/null @@ -1,94 +0,0 @@ -package moe.nea.firmament.util - -import io.github.moulberry.repo.data.Coordinate -import java.util.concurrent.ConcurrentLinkedQueue -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.screen.ingame.HandledScreen -import net.minecraft.client.render.WorldRenderer -import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket -import net.minecraft.registry.BuiltinRegistries -import net.minecraft.registry.RegistryKeys -import net.minecraft.registry.RegistryWrapper -import net.minecraft.resource.ReloadableResourceManagerImpl -import net.minecraft.text.Text -import net.minecraft.util.math.BlockPos -import moe.nea.firmament.events.TickEvent - -object MC { - - private val messageQueue = ConcurrentLinkedQueue<Text>() - - init { - TickEvent.subscribe { - while (true) { - inGameHud.chatHud.addMessage(messageQueue.poll() ?: break) - } - while (true) { - (nextTickTodos.poll() ?: break).invoke() - } - } - } - - fun sendChat(text: Text) { - if (instance.isOnThread) - inGameHud.chatHud.addMessage(text) - else - messageQueue.add(text) - } - - fun sendServerCommand(command: String) { - val nh = player?.networkHandler ?: return - nh.sendPacket( - CommandExecutionC2SPacket( - command, - ) - ) - } - - fun sendServerChat(text: String) { - player?.networkHandler?.sendChatMessage(text) - } - - fun sendCommand(command: String) { - player?.networkHandler?.sendCommand(command) - } - - fun onMainThread(block: () -> Unit) { - if (instance.isOnThread) - block() - else - instance.send(block) - } - - private val nextTickTodos = ConcurrentLinkedQueue<() -> Unit>() - fun nextTick(function: () -> Unit) { - nextTickTodos.add(function) - } - - - inline val resourceManager get() = (instance.resourceManager as ReloadableResourceManagerImpl) - inline val worldRenderer: WorldRenderer get() = instance.worldRenderer - inline val networkHandler get() = player?.networkHandler - inline val instance get() = MinecraftClient.getInstance() - inline val keyboard get() = instance.keyboard - inline val textureManager get() = instance.textureManager - inline val inGameHud get() = instance.inGameHud - inline val font get() = instance.textRenderer - inline val soundManager get() = instance.soundManager - inline val player get() = instance.player - inline val camera get() = instance.cameraEntity - inline val guiAtlasManager get() = instance.guiAtlasManager - inline val world get() = instance.world - inline var screen - get() = instance.currentScreen - set(value) = instance.setScreen(value) - inline val handledScreen: HandledScreen<*>? get() = instance.currentScreen as? HandledScreen<*> - inline val window get() = instance.window - inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager - val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup() - val defaultItems = defaultRegistries.getWrapperOrThrow(RegistryKeys.ITEM) -} - - -val Coordinate.blockPos: BlockPos - get() = BlockPos(x, y, z) diff --git a/src/main/kotlin/moe/nea/firmament/util/MinecraftDispatcher.kt b/src/main/kotlin/moe/nea/firmament/util/MinecraftDispatcher.kt deleted file mode 100644 index d1f22a9..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/MinecraftDispatcher.kt +++ /dev/null @@ -1,8 +0,0 @@ - - -package moe.nea.firmament.util - -import kotlinx.coroutines.asCoroutineDispatcher -import net.minecraft.client.MinecraftClient - -val MinecraftDispatcher by lazy { MinecraftClient.getInstance().asCoroutineDispatcher() } diff --git a/src/main/kotlin/moe/nea/firmament/util/MoulConfigFragment.kt b/src/main/kotlin/moe/nea/firmament/util/MoulConfigFragment.kt deleted file mode 100644 index 36132cd..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/MoulConfigFragment.kt +++ /dev/null @@ -1,44 +0,0 @@ - - -package moe.nea.firmament.util - -import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper -import io.github.notenoughupdates.moulconfig.gui.GuiContext -import io.github.notenoughupdates.moulconfig.gui.GuiImmediateContext -import me.shedaniel.math.Point -import net.minecraft.client.gui.DrawContext - -class MoulConfigFragment( - context: GuiContext, - val position: Point, - val dismiss: () -> Unit -) : GuiComponentWrapper(context) { - init { - this.init(MC.instance, MC.screen!!.width, MC.screen!!.height) - } - - override fun createContext(drawContext: DrawContext?): GuiImmediateContext { - val oldContext = super.createContext(drawContext) - return oldContext.translated( - position.x, - position.y, - context.root.width, - context.root.height, - ) - } - - - override fun render(drawContext: DrawContext?, i: Int, j: Int, f: Float) { - val ctx = createContext(drawContext) - val m = drawContext!!.matrices - m.push() - m.translate(position.x.toFloat(), position.y.toFloat(), 0F) - context.root.render(ctx) - m.pop() - ctx.renderContext.doDrawTooltip() - } - - override fun close() { - dismiss() - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt b/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt deleted file mode 100644 index 00561d1..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/MoulConfigUtils.kt +++ /dev/null @@ -1,230 +0,0 @@ - - -package moe.nea.firmament.util - -import io.github.notenoughupdates.moulconfig.common.MyResourceLocation -import io.github.notenoughupdates.moulconfig.gui.CloseEventListener -import io.github.notenoughupdates.moulconfig.gui.GuiComponentWrapper -import io.github.notenoughupdates.moulconfig.gui.GuiContext -import io.github.notenoughupdates.moulconfig.observer.GetSetter -import io.github.notenoughupdates.moulconfig.xml.ChildCount -import io.github.notenoughupdates.moulconfig.xml.XMLContext -import io.github.notenoughupdates.moulconfig.xml.XMLGuiLoader -import io.github.notenoughupdates.moulconfig.xml.XMLUniverse -import io.github.notenoughupdates.moulconfig.xml.XSDGenerator -import java.io.File -import java.util.function.Supplier -import javax.xml.namespace.QName -import me.shedaniel.math.Color -import org.w3c.dom.Element -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import net.minecraft.client.gui.screen.Screen -import moe.nea.firmament.gui.BarComponent -import moe.nea.firmament.gui.FirmButtonComponent -import moe.nea.firmament.gui.FirmHoverComponent -import moe.nea.firmament.gui.FixedComponent -import moe.nea.firmament.gui.ImageComponent -import moe.nea.firmament.gui.TickComponent - -object MoulConfigUtils { - val firmUrl = "http://firmament.nea.moe/moulconfig" - val universe = XMLUniverse.getDefaultUniverse().also { uni -> - uni.registerMapper(java.awt.Color::class.java) { - if (it.startsWith("#")) { - val hexString = it.substring(1) - val hex = hexString.toInt(16) - if (hexString.length == 6) { - return@registerMapper java.awt.Color(hex) - } - if (hexString.length == 8) { - return@registerMapper java.awt.Color(hex, true) - } - error("Hexcolor $it needs to be exactly 6 or 8 hex digits long") - } - return@registerMapper java.awt.Color(it.toInt(), true) - } - uni.registerMapper(Color::class.java) { - val color = uni.mapXMLObject(it, java.awt.Color::class.java) - Color.ofRGBA(color.red, color.green, color.blue, color.alpha) - } - uni.registerLoader(object : XMLGuiLoader.Basic<BarComponent> { - override fun getName(): QName { - return QName(firmUrl, "Bar") - } - - override fun createInstance(context: XMLContext<*>, element: Element): BarComponent { - return BarComponent( - context.getPropertyFromAttribute(element, QName("progress"), Double::class.java)!!, - context.getPropertyFromAttribute(element, QName("total"), Double::class.java)!!, - context.getPropertyFromAttribute(element, QName("fillColor"), Color::class.java)!!.get(), - context.getPropertyFromAttribute(element, QName("emptyColor"), Color::class.java)!!.get(), - ) - } - - override fun getChildCount(): ChildCount { - return ChildCount.NONE - } - - override fun getAttributeNames(): Map<String, Boolean> { - return mapOf("progress" to true, "total" to true, "emptyColor" to true, "fillColor" to true) - } - }) - uni.registerLoader(object : XMLGuiLoader.Basic<FirmHoverComponent> { - override fun createInstance(context: XMLContext<*>, element: Element): FirmHoverComponent { - return FirmHoverComponent( - context.getChildFragment(element), - context.getPropertyFromAttribute(element, QName("lines"), List::class.java) as Supplier<List<String>>, - context.getPropertyFromAttribute(element, QName("delay"), Duration::class.java, 0.6.seconds), - ) - } - - override fun getName(): QName { - return QName(firmUrl, "Hover") - } - - override fun getChildCount(): ChildCount { - return ChildCount.ONE - } - - override fun getAttributeNames(): Map<String, Boolean> { - return mapOf( - "lines" to true, - "delay" to false, - ) - } - - }) - uni.registerLoader(object : XMLGuiLoader.Basic<FirmButtonComponent> { - override fun getName(): QName { - return QName(firmUrl, "Button") - } - - override fun createInstance(context: XMLContext<*>, element: Element): FirmButtonComponent { - return FirmButtonComponent( - context.getChildFragment(element), - context.getPropertyFromAttribute(element, QName("enabled"), Boolean::class.java) - ?: GetSetter.constant(true), - context.getPropertyFromAttribute(element, QName("noBackground"), Boolean::class.java, false), - context.getMethodFromAttribute(element, QName("onClick")), - ) - } - - override fun getChildCount(): ChildCount { - return ChildCount.ONE - } - - override fun getAttributeNames(): Map<String, Boolean> { - return mapOf("onClick" to true, "enabled" to false, "noBackground" to false) - } - }) - uni.registerLoader(object : XMLGuiLoader.Basic<ImageComponent> { - override fun createInstance(context: XMLContext<*>, element: Element): ImageComponent { - return ImageComponent( - context.getPropertyFromAttribute(element, QName("width"), Int::class.java)!!.get(), - context.getPropertyFromAttribute(element, QName("height"), Int::class.java)!!.get(), - context.getPropertyFromAttribute(element, QName("resource"), MyResourceLocation::class.java)!!, - context.getPropertyFromAttribute(element, QName("u1"), Float::class.java, 0f), - context.getPropertyFromAttribute(element, QName("u2"), Float::class.java, 1f), - context.getPropertyFromAttribute(element, QName("v1"), Float::class.java, 0f), - context.getPropertyFromAttribute(element, QName("v2"), Float::class.java, 1f), - ) - } - - override fun getName(): QName { - return QName(firmUrl, "Image") - } - - override fun getChildCount(): ChildCount { - return ChildCount.NONE - } - - override fun getAttributeNames(): Map<String, Boolean> { - return mapOf( - "width" to true, "height" to true, - "resource" to true, - "u1" to false, - "u2" to false, - "v1" to false, - "v2" to false, - ) - } - }) - uni.registerLoader(object : XMLGuiLoader.Basic<TickComponent> { - override fun createInstance(context: XMLContext<*>, element: Element): TickComponent { - return TickComponent(context.getMethodFromAttribute(element, QName("tick"))) - } - - override fun getName(): QName { - return QName(firmUrl, "Tick") - } - - override fun getChildCount(): ChildCount { - return ChildCount.NONE - } - - override fun getAttributeNames(): Map<String, Boolean> { - return mapOf("tick" to true) - } - }) - uni.registerLoader(object : XMLGuiLoader.Basic<FixedComponent> { - override fun createInstance(context: XMLContext<*>, element: Element): FixedComponent { - return FixedComponent( - context.getPropertyFromAttribute(element, QName("width"), Int::class.java) - ?: error("Requires width specified"), - context.getPropertyFromAttribute(element, QName("height"), Int::class.java) - ?: error("Requires height specified"), - context.getChildFragment(element) - ) - } - - override fun getName(): QName { - return QName(firmUrl, "Fixed") - } - - override fun getChildCount(): ChildCount { - return ChildCount.ONE - } - - override fun getAttributeNames(): Map<String, Boolean> { - return mapOf("width" to true, "height" to true) - } - }) - } - - fun generateXSD( - file: File, - namespace: String - ) { - val generator = XSDGenerator(universe, namespace) - generator.writeAll() - generator.dumpToFile(file) - } - - @JvmStatic - fun main(args: Array<out String>) { - generateXSD(File("MoulConfig.xsd"), XMLUniverse.MOULCONFIG_XML_NS) - generateXSD(File("MoulConfig.Firmament.xsd"), firmUrl) - File("wrapper.xsd").writeText(""" -<?xml version="1.0" encoding="UTF-8" ?> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <xs:import namespace="http://notenoughupdates.org/moulconfig" schemaLocation="MoulConfig.xsd"/> - <xs:import namespace="http://firmament.nea.moe/moulconfig" schemaLocation="MoulConfig.Firmament.xsd"/> -</xs:schema> - """.trimIndent()) - } - - fun loadScreen(name: String, bindTo: Any, parent: Screen?): Screen { - return object : GuiComponentWrapper(loadGui(name, bindTo)) { - override fun close() { - if (context.onBeforeClose() == CloseEventListener.CloseAction.NO_OBJECTIONS_TO_CLOSE) { - client!!.setScreen(parent) - } - } - } - } - - fun loadGui(name: String, bindTo: Any): GuiContext { - return GuiContext(universe.load(bindTo, MyResourceLocation("firmament", "gui/$name.xml"))) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/MutableMapWithMaxSize.kt b/src/main/kotlin/moe/nea/firmament/util/MutableMapWithMaxSize.kt deleted file mode 100644 index 067e652..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/MutableMapWithMaxSize.kt +++ /dev/null @@ -1,38 +0,0 @@ - -package moe.nea.firmament.util - -fun <K, V> mutableMapWithMaxSize(maxSize: Int): MutableMap<K, V> = object : LinkedHashMap<K, V>() { - override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>): Boolean { - return size > maxSize - } -} - -fun <T, R> ((T) -> R).memoizeIdentity(maxCacheSize: Int): (T) -> R { - val memoized = { it: IdentityCharacteristics<T> -> - this(it.value) - }.memoize(maxCacheSize) - return { memoized(IdentityCharacteristics(it)) } -} - -@PublishedApi -internal val SENTINEL_NULL = java.lang.Object() - -/** - * Requires the map to only contain values of type [R] or [SENTINEL_NULL]. This is ensured if the map is only ever - * accessed via this function. - */ -inline fun <T, R> MutableMap<T, Any>.computeNullableFunction(key: T, crossinline func: () -> R): R { - val value = this.getOrPut(key) { - func() ?: SENTINEL_NULL - } - @Suppress("UNCHECKED_CAST") - return if (value === SENTINEL_NULL) null as R - else value as R -} - -fun <T, R> ((T) -> R).memoize(maxCacheSize: Int): (T) -> R { - val map = mutableMapWithMaxSize<T, Any>(maxCacheSize) - return { - map.computeNullableFunction(it) { this@memoize(it) } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/SBData.kt b/src/main/kotlin/moe/nea/firmament/util/SBData.kt deleted file mode 100644 index b30c6fb..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/SBData.kt +++ /dev/null @@ -1,66 +0,0 @@ -package moe.nea.firmament.util - -import java.util.UUID -import net.hypixel.modapi.HypixelModAPI -import net.hypixel.modapi.packet.impl.clientbound.event.ClientboundLocationPacket -import kotlin.jvm.optionals.getOrNull -import kotlin.time.Duration.Companion.seconds -import moe.nea.firmament.events.AllowChatEvent -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.events.ServerConnectedEvent -import moe.nea.firmament.events.SkyblockServerUpdateEvent -import moe.nea.firmament.events.WorldReadyEvent - -object SBData { - private val profileRegex = "Profile ID: ([a-z0-9\\-]+)".toRegex() - val profileSuggestTexts = listOf( - "CLICK THIS TO SUGGEST IT IN CHAT [DASHES]", - "CLICK THIS TO SUGGEST IT IN CHAT [NO DASHES]", - ) - var profileId: UUID? = null - - private var hasReceivedProfile = false - var locraw: Locraw? = null - val skyblockLocation: SkyBlockIsland? get() = locraw?.skyblockLocation - val hasValidLocraw get() = locraw?.server !in listOf("limbo", null) - val isOnSkyblock get() = locraw?.gametype == "SKYBLOCK" - var lastProfileIdRequest = TimeMark.farPast() - fun init() { - ServerConnectedEvent.subscribe { - HypixelModAPI.getInstance().subscribeToEventPacket(ClientboundLocationPacket::class.java) - } - HypixelModAPI.getInstance().createHandler(ClientboundLocationPacket::class.java) { - MC.onMainThread { - val lastLocraw = locraw - locraw = Locraw(it.serverName, - it.serverType.getOrNull()?.name?.uppercase(), - it.mode.getOrNull(), - it.map.getOrNull()) - SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, null)) - } - } - SkyblockServerUpdateEvent.subscribe { - if (!hasReceivedProfile && isOnSkyblock && lastProfileIdRequest.passedTime() > 30.seconds) { - lastProfileIdRequest = TimeMark.now() - MC.sendServerCommand("profileid") - } - } - AllowChatEvent.subscribe { event -> - if (event.unformattedString in profileSuggestTexts && lastProfileIdRequest.passedTime() < 5.seconds) { - event.cancel() - } - } - ProcessChatEvent.subscribe(receivesCancelled = true) { event -> - val profileMatch = profileRegex.matchEntire(event.unformattedString) - if (profileMatch != null) { - try { - profileId = UUID.fromString(profileMatch.groupValues[1]) - hasReceivedProfile = true - } catch (e: IllegalArgumentException) { - profileId = null - e.printStackTrace() - } - } - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/ScoreboardUtil.kt b/src/main/kotlin/moe/nea/firmament/util/ScoreboardUtil.kt deleted file mode 100644 index 4311971..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/ScoreboardUtil.kt +++ /dev/null @@ -1,45 +0,0 @@ - - -package moe.nea.firmament.util - -import java.util.* -import net.minecraft.client.gui.hud.InGameHud -import net.minecraft.scoreboard.ScoreboardDisplaySlot -import net.minecraft.scoreboard.Team -import net.minecraft.text.StringVisitable -import net.minecraft.text.Style -import net.minecraft.text.Text -import net.minecraft.util.Formatting - -fun getScoreboardLines(): List<Text> { - val scoreboard = MC.player?.scoreboard ?: return listOf() - val activeObjective = scoreboard.getObjectiveForSlot(ScoreboardDisplaySlot.SIDEBAR) ?: return listOf() - return scoreboard.getScoreboardEntries(activeObjective) - .filter { !it.hidden() } - .sortedWith(InGameHud.SCOREBOARD_ENTRY_COMPARATOR) - .take(15).map { - val team = scoreboard.getScoreHolderTeam(it.owner) - val text = it.name() - Team.decorateName(team, text) - } -} - - -fun Text.formattedString(): String { - val sb = StringBuilder() - visit(StringVisitable.StyledVisitor<Unit> { style, string -> - val c = Formatting.byName(style.color?.name) - if (c != null) { - sb.append("§${c.code}") - } - if (style.isUnderlined) { - sb.append("§n") - } - if (style.isBold) { - sb.append("§l") - } - sb.append(string) - Optional.empty() - }, Style.EMPTY) - return sb.toString().replace("§[^a-f0-9]".toRegex(), "") -} diff --git a/src/main/kotlin/moe/nea/firmament/util/ScreenUtil.kt b/src/main/kotlin/moe/nea/firmament/util/ScreenUtil.kt deleted file mode 100644 index 99d77fb..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/ScreenUtil.kt +++ /dev/null @@ -1,38 +0,0 @@ - - -package moe.nea.firmament.util - -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents -import net.minecraft.client.MinecraftClient -import net.minecraft.client.gui.screen.Screen -import moe.nea.firmament.Firmament - -object ScreenUtil { - init { - ClientTickEvents.START_CLIENT_TICK.register(::onTick) - } - - private fun onTick(minecraft: MinecraftClient) { - if (nextOpenedGui != null) { - val p = minecraft.player - if (p?.currentScreenHandler != null) { - p.closeHandledScreen() - } - minecraft.setScreen(nextOpenedGui) - nextOpenedGui = null - } - } - - private var nextOpenedGui: Screen? = null - - fun setScreenLater(nextScreen: Screen?) { - val nog = nextOpenedGui - if (nog != null) { - Firmament.logger.warn("Setting screen ${if (nextScreen == null) "null" else nextScreen::class.qualifiedName} to be opened later, but ${nog::class.qualifiedName} is already queued.") - return - } - nextOpenedGui = nextScreen - } - - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/SequenceUtil.kt b/src/main/kotlin/moe/nea/firmament/util/SequenceUtil.kt deleted file mode 100644 index 7b5bad0..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/SequenceUtil.kt +++ /dev/null @@ -1,11 +0,0 @@ - - -package moe.nea.firmament.util - -fun <T : Any> T.iterate(iterator: (T) -> T?): Sequence<T> = sequence { - var x: T? = this@iterate - while (x != null) { - yield(x) - x = iterator(x) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/SkyBlockIsland.kt b/src/main/kotlin/moe/nea/firmament/util/SkyBlockIsland.kt deleted file mode 100644 index bd0567d..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/SkyBlockIsland.kt +++ /dev/null @@ -1,42 +0,0 @@ - -package moe.nea.firmament.util - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import moe.nea.firmament.repo.RepoManager - -@Serializable(with = SkyBlockIsland.Serializer::class) -class SkyBlockIsland -private constructor( - val locrawMode: String, -) { - - object Serializer : KSerializer<SkyBlockIsland> { - override val descriptor: SerialDescriptor - get() = PrimitiveSerialDescriptor("SkyBlockIsland", PrimitiveKind.STRING) - - override fun deserialize(decoder: Decoder): SkyBlockIsland { - return forMode(decoder.decodeString()) - } - - override fun serialize(encoder: Encoder, value: SkyBlockIsland) { - encoder.encodeString(value.locrawMode) - } - } - companion object { - private val allIslands = mutableMapOf<String, SkyBlockIsland>() - fun forMode(mode: String): SkyBlockIsland = allIslands.computeIfAbsent(mode, ::SkyBlockIsland) - val HUB = forMode("hub") - val PRIVATE_ISLAND = forMode("dynamic") - val RIFT = forMode("rift") - } - - val userFriendlyName - get() = RepoManager.neuRepo.constants.islands.areaNames - .getOrDefault(locrawMode, locrawMode) -} diff --git a/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt b/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt deleted file mode 100644 index 59b1d2c..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/SkyblockId.kt +++ /dev/null @@ -1,149 +0,0 @@ - - -@file:UseSerializers(DashlessUUIDSerializer::class) - -package moe.nea.firmament.util - -import io.github.moulberry.repo.data.NEUItem -import io.github.moulberry.repo.data.Rarity -import java.util.UUID -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import kotlinx.serialization.json.Json -import net.minecraft.component.DataComponentTypes -import net.minecraft.component.type.NbtComponent -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NbtCompound -import net.minecraft.util.Identifier -import moe.nea.firmament.repo.set -import moe.nea.firmament.util.json.DashlessUUIDSerializer - -/** - * A skyblock item id, as used by the NEU repo. - * This is not exactly the format used by HyPixel, but is mostly the same. - * Usually this id splits an id used by HyPixel into more sub items. For example `PET` becomes `$PET_ID;$PET_RARITY`, - * with those values extracted from other metadata. - */ -@JvmInline -@Serializable -value class SkyblockId(val neuItem: String) { - val identifier - get() = Identifier.of("skyblockitem", - neuItem.lowercase().replace(";", "__") - .replace(":", "___") - .replace(illlegalPathRegex) { - it.value.toCharArray() - .joinToString("") { "__" + it.code.toString(16).padStart(4, '0') } - }) - - override fun toString(): String { - return neuItem - } - - /** - * A bazaar stock item id, as returned by the HyPixel bazaar api endpoint. - * These are not equivalent to the in-game ids, or the NEU repo ids, and in fact, do not refer to items, but instead - * to bazaar stocks. The main difference from [SkyblockId]s is concerning enchanted books. There are probably more, - * but for now this holds. - */ - @JvmInline - @Serializable - value class BazaarStock(val bazaarId: String) { - fun toRepoId(): SkyblockId { - bazaarEnchantmentRegex.matchEntire(bazaarId)?.let { - return SkyblockId("${it.groupValues[1]};${it.groupValues[2]}") - } - return SkyblockId(bazaarId.replace(":", "-")) - } - } - - companion object { - val COINS: SkyblockId = SkyblockId("SKYBLOCK_COIN") - private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex() - val NULL: SkyblockId = SkyblockId("null") - val PET_NULL: SkyblockId = SkyblockId("null_pet") - private val illlegalPathRegex = "[^a-z0-9_.-/]".toRegex() - } -} - -val NEUItem.skyblockId get() = SkyblockId(skyblockItemId) - -@Serializable -data class HypixelPetInfo( - val type: String, - val tier: Rarity, - val exp: Double = 0.0, - val candyUsed: Int = 0, - val uuid: UUID? = null, -) { - val skyblockId get() = SkyblockId("${type.uppercase()};${tier.ordinal}") -} - -private val jsonparser = Json { ignoreUnknownKeys = true } - -val ItemStack.extraAttributes: NbtCompound - get() { - val customData = get(DataComponentTypes.CUSTOM_DATA) ?: run { - val component = NbtComponent.of(NbtCompound()) - set(DataComponentTypes.CUSTOM_DATA, component) - component - } - return customData.nbt - } - -val ItemStack.skyblockUUIDString: String? - get() = extraAttributes.getString("uuid")?.takeIf { it.isNotBlank() } - -val ItemStack.skyblockUUID: UUID? - get() = skyblockUUIDString?.let { UUID.fromString(it) } - -val ItemStack.petData: HypixelPetInfo? - get() { - val jsonString = extraAttributes.getString("petInfo") - if (jsonString.isNullOrBlank()) return null - return runCatching { jsonparser.decodeFromString<HypixelPetInfo>(jsonString) } - .getOrElse { return null } - } - -fun ItemStack.setSkyBlockFirmamentUiId(uiId: String) = setSkyBlockId(SkyblockId("FIRMAMENT_UI_$uiId")) -fun ItemStack.setSkyBlockId(skyblockId: SkyblockId): ItemStack { - this.extraAttributes["id"] = skyblockId.neuItem - return this -} - -val ItemStack.skyBlockId: SkyblockId? - get() { - return when (val id = extraAttributes.getString("id")) { - "" -> { - null - } - - "PET" -> { - petData?.skyblockId ?: SkyblockId.PET_NULL - } - - "RUNE", "UNIQUE_RUNE" -> { - val runeData = extraAttributes.getCompound("runes") - val runeKind = runeData.keys.singleOrNull() - if (runeKind == null) SkyblockId("RUNE") - else SkyblockId("${runeKind.uppercase()}_RUNE;${runeData.getInt(runeKind)}") - } - - "ABICASE" -> { - SkyblockId("ABICASE_${extraAttributes.getString("model").uppercase()}") - } - - "ENCHANTED_BOOK" -> { - val enchantmentData = extraAttributes.getCompound("enchantments") - val enchantName = enchantmentData.keys.singleOrNull() - if (enchantName == null) SkyblockId("ENCHANTED_BOOK") - else SkyblockId("${enchantName.uppercase()};${enchantmentData.getInt(enchantName)}") - } - - // TODO: PARTY_HAT_CRAB{,_ANIMATED,_SLOTH},POTION - else -> { - SkyblockId(id) - } - } - } - diff --git a/src/main/kotlin/moe/nea/firmament/util/SortedMapSerializer.kt b/src/main/kotlin/moe/nea/firmament/util/SortedMapSerializer.kt deleted file mode 100644 index baa10ad..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/SortedMapSerializer.kt +++ /dev/null @@ -1,25 +0,0 @@ - - -package moe.nea.firmament.util - -import java.util.SortedMap -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.MapSerializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder - -class SortedMapSerializer<K : Comparable<K>, V>(val keyDelegate: KSerializer<K>, val valueDelegate: KSerializer<V>) : - KSerializer<SortedMap<K, V>> { - val mapSerializer = MapSerializer(keyDelegate, valueDelegate) - override val descriptor: SerialDescriptor - get() = mapSerializer.descriptor - - override fun deserialize(decoder: Decoder): SortedMap<K, V> { - return (mapSerializer.deserialize(decoder).toSortedMap(Comparator.naturalOrder())) - } - - override fun serialize(encoder: Encoder, value: SortedMap<K, V>) { - mapSerializer.serialize(encoder, value) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/TemplateUtil.kt b/src/main/kotlin/moe/nea/firmament/util/TemplateUtil.kt deleted file mode 100644 index 11100e9..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/TemplateUtil.kt +++ /dev/null @@ -1,85 +0,0 @@ - - -package moe.nea.firmament.util - -import java.util.* -import kotlinx.serialization.DeserializationStrategy -import kotlinx.serialization.SerializationStrategy -import kotlinx.serialization.serializer -import moe.nea.firmament.Firmament - -object TemplateUtil { - - @JvmStatic - fun getTemplatePrefix(data: String): String? { - val decoded = maybeFromBase64Encoded(data) ?: return null - return decoded.replaceAfter("/", "", "").ifBlank { null } - } - - @JvmStatic - fun intoBase64Encoded(raw: String): String { - return Base64.getEncoder().encodeToString(raw.encodeToByteArray()) - } - - private val base64Alphabet = charArrayOf( - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' - ) - - @JvmStatic - fun maybeFromBase64Encoded(raw: String): String? { - val raw = raw.trim() - if (raw.any { it !in base64Alphabet }) { - return null - } - return try { - Base64.getDecoder().decode(raw).decodeToString() - } catch (ex: Exception) { - null - } - } - - - /** - * Returns a base64 encoded string, truncated such that for all `x`, `x.startsWith(prefix)` implies - * `base64Encoded(x).startsWith(getPrefixComparisonSafeBase64Encoding(prefix))` - * (however, the inverse may not always be true). - */ - @JvmStatic - fun getPrefixComparisonSafeBase64Encoding(prefix: String): String { - val rawEncoded = - Base64.getEncoder().encodeToString(prefix.encodeToByteArray()) - .replace("=", "") - return rawEncoded.substring(0, rawEncoded.length - rawEncoded.length % 4) - } - - inline fun <reified T> encodeTemplate(sharePrefix: String, data: T): String = - encodeTemplate(sharePrefix, data, serializer()) - - fun <T> encodeTemplate(sharePrefix: String, data: T, serializer: SerializationStrategy<T>): String { - require(sharePrefix.endsWith("/")) - return intoBase64Encoded(sharePrefix + Firmament.json.encodeToString(serializer, data)) - } - - inline fun <reified T : Any> maybeDecodeTemplate(sharePrefix: String, data: String): T? = - maybeDecodeTemplate(sharePrefix, data, serializer()) - - fun <T : Any> maybeDecodeTemplate(sharePrefix: String, data: String, serializer: DeserializationStrategy<T>): T? { - require(sharePrefix.endsWith("/")) - val data = data.trim() - if (!data.startsWith(getPrefixComparisonSafeBase64Encoding(sharePrefix))) - return null - val decoded = maybeFromBase64Encoded(data) ?: return null - if (!decoded.startsWith(sharePrefix)) - return null - return try { - Firmament.json.decodeFromString<T>(serializer, decoded.substring(sharePrefix.length)) - } catch (e: Exception) { - null - } - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/TimeMark.kt b/src/main/kotlin/moe/nea/firmament/util/TimeMark.kt deleted file mode 100644 index 1264212..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/TimeMark.kt +++ /dev/null @@ -1,44 +0,0 @@ - - -package moe.nea.firmament.util - -import kotlin.time.Duration -import kotlin.time.Duration.Companion.milliseconds - -class TimeMark private constructor(private val timeMark: Long) : Comparable<TimeMark> { - fun passedTime() = if (timeMark == 0L) Duration.INFINITE else (System.currentTimeMillis() - timeMark).milliseconds - - operator fun minus(other: TimeMark): Duration { - if (other.timeMark == timeMark) - return 0.milliseconds - if (other.timeMark == 0L) - return Duration.INFINITE - if (timeMark == 0L) - return -Duration.INFINITE - return (timeMark - other.timeMark).milliseconds - } - - companion object { - 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 hashCode(): Int { - return timeMark.hashCode() - } - - override fun equals(other: Any?): Boolean { - return other is TimeMark && other.timeMark == timeMark - } - - override fun compareTo(other: TimeMark): Int { - return this.timeMark.compareTo(other.timeMark) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/Timer.kt b/src/main/kotlin/moe/nea/firmament/util/Timer.kt deleted file mode 100644 index 6e9b467..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/Timer.kt +++ /dev/null @@ -1,25 +0,0 @@ - - -package moe.nea.firmament.util - -import kotlin.time.Duration -import kotlin.time.ExperimentalTime -import kotlin.time.TimeSource - -@OptIn(ExperimentalTime::class) -class Timer { - private var mark: TimeSource.Monotonic.ValueTimeMark? = null - - fun timePassed(): Duration { - return mark?.elapsedNow() ?: Duration.INFINITE - } - - fun markNow() { - mark = TimeSource.Monotonic.markNow() - } - - fun markFarPast() { - mark = null - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/WarpUtil.kt b/src/main/kotlin/moe/nea/firmament/util/WarpUtil.kt deleted file mode 100644 index 8fca6f3..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/WarpUtil.kt +++ /dev/null @@ -1,75 +0,0 @@ - -package moe.nea.firmament.util - -import io.github.moulberry.repo.constants.Islands -import io.github.moulberry.repo.constants.Islands.Warp -import kotlinx.serialization.Serializable -import kotlinx.serialization.serializer -import kotlin.math.sqrt -import kotlin.time.Duration.Companion.seconds -import net.minecraft.text.Text -import net.minecraft.util.math.Position -import moe.nea.firmament.events.ProcessChatEvent -import moe.nea.firmament.repo.RepoManager -import moe.nea.firmament.util.data.ProfileSpecificDataHolder - -object WarpUtil { - val warps: List<Islands.Warp> get() = RepoManager.neuRepo.constants.islands.warps - - @Serializable - data class Data( - val excludedWarps: MutableSet<String> = mutableSetOf(), - ) - - object DConfig : ProfileSpecificDataHolder<Data>(serializer(), "warp-util", ::Data) - - private var lastAttemptedWarp = "" - private var lastWarpAttempt = TimeMark.farPast() - fun findNearestWarp(island: SkyBlockIsland, pos: Position): Islands.Warp? { - return warps.asSequence().filter { it.mode == island.locrawMode }.minByOrNull { - if (DConfig.data?.excludedWarps?.contains(it.warp) == true) { - return@minByOrNull Double.MAX_VALUE - } else { - return@minByOrNull squaredDist(pos, it) - } - } - } - - private fun squaredDist(pos: Position, warp: Warp): Double { - val dx = pos.x - warp.x - val dy = pos.y - warp.y - val dz = pos.z - warp.z - return dx * dx + dy * dy + dz * dz - } - - fun teleportToNearestWarp(island: SkyBlockIsland, pos: Position) { - val nearestWarp = findNearestWarp(island, pos) - if (nearestWarp == null) { - MC.sendChat(Text.literal("Could not find an unlocked warp in ${island.userFriendlyName}")) - return - } - if (island == SBData.skyblockLocation - && sqrt(squaredDist(pos, nearestWarp)) > 1.1 * sqrt(squaredDist((MC.player ?: return).pos, nearestWarp)) - ) { - return - } - MC.sendServerCommand("warp ${nearestWarp.warp}") - } - - init { - ProcessChatEvent.subscribe { - if (it.unformattedString == "You haven't unlocked this fast travel destination!" - && lastWarpAttempt.passedTime() < 2.seconds - ) { - DConfig.data?.excludedWarps?.add(lastAttemptedWarp) - DConfig.markDirty() - MC.sendChat(Text.stringifiedTranslatable("firmament.warp-util.mark-excluded", lastAttemptedWarp)) - lastWarpAttempt = TimeMark.farPast() - } - if (it.unformattedString == "You may now fast travel to") { - DConfig.data?.excludedWarps?.clear() - DConfig.markDirty() - } - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/assertions.kt b/src/main/kotlin/moe/nea/firmament/util/assertions.kt deleted file mode 100644 index 6f2ed19..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/assertions.kt +++ /dev/null @@ -1,25 +0,0 @@ - - -package moe.nea.firmament.util - -/** - * Less aggressive version of `require(obj != null)`, which fails in devenv but continues at runtime. - */ -inline fun <T : Any> assertNotNullOr(obj: T?, message: String? = null, block: () -> T): T { - if (message == null) - assert(obj != null) - else - assert(obj != null) { message } - return obj ?: block() -} - - -/** - * Less aggressive version of `require(condition)`, which fails in devenv but continues at runtime. - */ -inline fun assertTrueOr(condition: Boolean, block: () -> Unit) { - assert(condition) - if (!condition) block() -} - - diff --git a/src/main/kotlin/moe/nea/firmament/util/async/input.kt b/src/main/kotlin/moe/nea/firmament/util/async/input.kt deleted file mode 100644 index 9aab5cf..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/async/input.kt +++ /dev/null @@ -1,47 +0,0 @@ - - -package moe.nea.firmament.util.async - -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlin.coroutines.resume -import moe.nea.firmament.events.HandledScreenKeyPressedEvent -import moe.nea.firmament.keybindings.IKeyBinding - -private object InputHandler { - data class KeyInputContinuation(val keybind: IKeyBinding, val onContinue: () -> Unit) - - private val activeContinuations = mutableListOf<KeyInputContinuation>() - - fun registerContinuation(keyInputContinuation: KeyInputContinuation): () -> Unit { - synchronized(InputHandler) { - activeContinuations.add(keyInputContinuation) - } - return { - synchronized(this) { - activeContinuations.remove(keyInputContinuation) - } - } - } - - init { - HandledScreenKeyPressedEvent.subscribe { event -> - synchronized(InputHandler) { - val toRemove = activeContinuations.filter { - event.matches(it.keybind) - } - toRemove.forEach { it.onContinue() } - activeContinuations.removeAll(toRemove) - } - } - } -} - -suspend fun waitForInput(keybind: IKeyBinding): Unit = suspendCancellableCoroutine { cont -> - val unregister = - InputHandler.registerContinuation(InputHandler.KeyInputContinuation(keybind) { cont.resume(Unit) }) - cont.invokeOnCancellation { - unregister() - } -} - - diff --git a/src/main/kotlin/moe/nea/firmament/util/colorconversion.kt b/src/main/kotlin/moe/nea/firmament/util/colorconversion.kt deleted file mode 100644 index d7a5dad..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/colorconversion.kt +++ /dev/null @@ -1,13 +0,0 @@ - - -package moe.nea.firmament.util - -import net.minecraft.text.TextColor -import net.minecraft.util.DyeColor - -fun DyeColor.toShedaniel(): me.shedaniel.math.Color = - me.shedaniel.math.Color.ofOpaque(this.signColor) - -fun DyeColor.toTextColor(): TextColor = - TextColor.fromRgb(this.signColor) - diff --git a/src/main/kotlin/moe/nea/firmament/util/customgui/CoordRememberingSlot.kt b/src/main/kotlin/moe/nea/firmament/util/customgui/CoordRememberingSlot.kt deleted file mode 100644 index c61c711..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/customgui/CoordRememberingSlot.kt +++ /dev/null @@ -1,14 +0,0 @@ - -package moe.nea.firmament.util.customgui - -import net.minecraft.screen.slot.Slot - -interface CoordRememberingSlot { - fun rememberCoords_firmament() - fun restoreCoords_firmament() - fun getOriginalX_firmament(): Int - fun getOriginalY_firmament(): Int -} - -val Slot.originalX get() = (this as CoordRememberingSlot).getOriginalX_firmament() -val Slot.originalY get() = (this as CoordRememberingSlot).getOriginalY_firmament() diff --git a/src/main/kotlin/moe/nea/firmament/util/customgui/CustomGui.kt b/src/main/kotlin/moe/nea/firmament/util/customgui/CustomGui.kt deleted file mode 100644 index f9094b2..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/customgui/CustomGui.kt +++ /dev/null @@ -1,72 +0,0 @@ - -package moe.nea.firmament.util.customgui - -import me.shedaniel.math.Rectangle -import net.minecraft.client.gui.DrawContext -import net.minecraft.screen.slot.Slot -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.HandledScreenPushREIEvent - -abstract class CustomGui { - - abstract fun getBounds(): List<Rectangle> - - open fun moveSlot(slot: Slot) { - // TODO: return a Pair maybe? worth an investigation - } - - companion object { - @Subscribe - fun onExclusionZone(event: HandledScreenPushREIEvent) { - val customGui = event.screen.customGui ?: return - event.rectangles.addAll(customGui.getBounds()) - } - } - - open fun render( - drawContext: DrawContext, - delta: Float, - mouseX: Int, - mouseY: Int - ) { - } - - open fun mouseClick(mouseX: Double, mouseY: Double, button: Int): Boolean { - return false - } - - open fun afterSlotRender(context: DrawContext, slot: Slot) {} - open fun beforeSlotRender(context: DrawContext, slot: Slot) {} - open fun mouseScrolled(mouseX: Double, mouseY: Double, horizontalAmount: Double, verticalAmount: Double): Boolean { - return false - } - - open fun isClickOutsideBounds(mouseX: Double, mouseY: Double): Boolean { - return getBounds().none { it.contains(mouseX, mouseY) } - } - - open fun isPointWithinBounds( - x: Int, - y: Int, - width: Int, - height: Int, - pointX: Double, - pointY: Double, - ): Boolean { - return getBounds().any { it.contains(pointX, pointY) } && - Rectangle(x, y, width, height).contains(pointX, pointY) - } - - open fun isPointOverSlot(slot: Slot, xOffset: Int, yOffset: Int, pointX: Double, pointY: Double): Boolean { - return isPointWithinBounds(slot.x + xOffset, slot.y + yOffset, 16, 16, pointX, pointY) - } - - open fun onInit() {} - open fun shouldDrawForeground(): Boolean { - return true - } - - open fun onVoluntaryExit(): Boolean { - return true - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/customgui/HasCustomGui.kt b/src/main/kotlin/moe/nea/firmament/util/customgui/HasCustomGui.kt deleted file mode 100644 index edead2e..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/customgui/HasCustomGui.kt +++ /dev/null @@ -1,17 +0,0 @@ - -package moe.nea.firmament.util.customgui - -import net.minecraft.client.gui.screen.ingame.HandledScreen - -@Suppress("FunctionName") -interface HasCustomGui { - fun getCustomGui_Firmament(): CustomGui? - fun setCustomGui_Firmament(gui: CustomGui?) -} - -var <T : HandledScreen<*>> T.customGui: CustomGui? - get() = (this as HasCustomGui).getCustomGui_Firmament() - set(value) { - (this as HasCustomGui).setCustomGui_Firmament(value) - } - diff --git a/src/main/kotlin/moe/nea/firmament/util/data/DataHolder.kt b/src/main/kotlin/moe/nea/firmament/util/data/DataHolder.kt deleted file mode 100644 index 21a6014..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/data/DataHolder.kt +++ /dev/null @@ -1,62 +0,0 @@ - - -package moe.nea.firmament.util.data - -import java.nio.file.Path -import kotlinx.serialization.KSerializer -import kotlin.io.path.exists -import kotlin.io.path.readText -import kotlin.io.path.writeText -import moe.nea.firmament.Firmament - -abstract class DataHolder<T>( - val serializer: KSerializer<T>, - val name: String, - val default: () -> T -) : IDataHolder<T> { - - - final override var data: T - private set - - init { - data = readValueOrDefault() - IDataHolder.putDataHolder(this::class, this) - } - - private val file: Path get() = Firmament.CONFIG_DIR.resolve("$name.json") - - protected fun readValueOrDefault(): T { - if (file.exists()) - try { - return Firmament.json.decodeFromString( - serializer, - file.readText() - ) - } catch (e: Exception) {/* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/ - IDataHolder.badLoads.add(name) - Firmament.logger.error( - "Exception during loading of config file $name. This will reset this config.", - e - ) - } - return default() - } - - private fun writeValue(t: T) { - file.writeText(Firmament.json.encodeToString(serializer, t)) - } - - override fun save() { - writeValue(data) - } - - override fun load() { - data = readValueOrDefault() - } - - override fun markDirty() { - IDataHolder.markDirty(this::class) - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/data/IDataHolder.kt b/src/main/kotlin/moe/nea/firmament/util/data/IDataHolder.kt deleted file mode 100644 index 5d09bcd..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/data/IDataHolder.kt +++ /dev/null @@ -1,77 +0,0 @@ - - -package moe.nea.firmament.util.data - -import java.util.concurrent.CopyOnWriteArrayList -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents -import kotlin.reflect.KClass -import net.minecraft.client.MinecraftClient -import net.minecraft.server.command.CommandOutput -import net.minecraft.text.Text -import moe.nea.firmament.Firmament -import moe.nea.firmament.events.ScreenChangeEvent - -interface IDataHolder<T> { - companion object { - internal var badLoads: MutableList<String> = CopyOnWriteArrayList() - private val allConfigs: MutableMap<KClass<out IDataHolder<*>>, IDataHolder<*>> = mutableMapOf() - private val dirty: MutableSet<KClass<out IDataHolder<*>>> = mutableSetOf() - - internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) { - allConfigs[kClass] = inst - } - - fun <T : IDataHolder<K>, K> markDirty(kClass: KClass<T>) { - if (kClass !in allConfigs) { - Firmament.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'") - return - } - dirty.add(kClass) - } - - private fun performSaves() { - val toSave = dirty.toList().also { - dirty.clear() - } - for (it in toSave) { - val obj = allConfigs[it] - if (obj == null) { - Firmament.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'") - continue - } - obj.save() - } - } - - private fun warnForResetConfigs(player: CommandOutput) { - if (badLoads.isNotEmpty()) { - player.sendMessage( - Text.literal( - "The following configs have been reset: ${badLoads.joinToString(", ")}. " + - "This can be intentional, but probably isn't." - ) - ) - badLoads.clear() - } - } - - fun registerEvents() { - ScreenChangeEvent.subscribe { event -> - performSaves() - val p = MinecraftClient.getInstance().player - if (p != null) { - warnForResetConfigs(p) - } - } - ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { - performSaves() - }) - } - - } - - val data: T - fun save() - fun markDirty() - fun load() -} diff --git a/src/main/kotlin/moe/nea/firmament/util/data/ProfileSpecificDataHolder.kt b/src/main/kotlin/moe/nea/firmament/util/data/ProfileSpecificDataHolder.kt deleted file mode 100644 index 1cd4f22..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/data/ProfileSpecificDataHolder.kt +++ /dev/null @@ -1,84 +0,0 @@ - - -package moe.nea.firmament.util.data - -import java.nio.file.Path -import java.util.UUID -import kotlinx.serialization.KSerializer -import kotlin.io.path.createDirectories -import kotlin.io.path.deleteExisting -import kotlin.io.path.exists -import kotlin.io.path.extension -import kotlin.io.path.listDirectoryEntries -import kotlin.io.path.nameWithoutExtension -import kotlin.io.path.readText -import kotlin.io.path.writeText -import moe.nea.firmament.Firmament -import moe.nea.firmament.util.SBData - -abstract class ProfileSpecificDataHolder<S>( - private val dataSerializer: KSerializer<S>, - val configName: String, - private val configDefault: () -> S -) : IDataHolder<S?> { - - var allConfigs: MutableMap<UUID, S> - - override val data: S? - get() = SBData.profileId?.let { - allConfigs.computeIfAbsent(it) { configDefault() } - } - - init { - allConfigs = readValues() - IDataHolder.putDataHolder(this::class, this) - } - - private val configDirectory: Path get() = Firmament.CONFIG_DIR.resolve("profiles").resolve(configName) - - private fun readValues(): MutableMap<UUID, S> { - if (!configDirectory.exists()) { - configDirectory.createDirectories() - } - val profileFiles = configDirectory.listDirectoryEntries() - return profileFiles - .filter { it.extension == "json" } - .mapNotNull { - try { - UUID.fromString(it.nameWithoutExtension) to Firmament.json.decodeFromString(dataSerializer, it.readText()) - } catch (e: Exception) { /* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/ - IDataHolder.badLoads.add(configName) - Firmament.logger.error( - "Exception during loading of profile specific config file $it ($configName). This will reset that profiles config.", - e - ) - null - } - }.toMap().toMutableMap() - } - - override fun save() { - if (!configDirectory.exists()) { - configDirectory.createDirectories() - } - val c = allConfigs - configDirectory.listDirectoryEntries().forEach { - if (it.nameWithoutExtension !in c.mapKeys { it.toString() }) { - it.deleteExisting() - } - } - c.forEach { (name, value) -> - val f = configDirectory.resolve("$name.json") - f.writeText(Firmament.json.encodeToString(dataSerializer, value)) - } - } - - override fun markDirty() { - IDataHolder.markDirty(this::class) - } - - override fun load() { - allConfigs = readValues() - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/filter/IteratorFilterSet.kt b/src/main/kotlin/moe/nea/firmament/util/filter/IteratorFilterSet.kt deleted file mode 100644 index 483b8d9..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/filter/IteratorFilterSet.kt +++ /dev/null @@ -1,33 +0,0 @@ - -package moe.nea.firmament.util.filter - -abstract class IteratorFilterSet<K>(val original: java.util.Set<K>) : java.util.Set<K> by original { - abstract fun shouldKeepElement(element: K): Boolean - - override fun iterator(): MutableIterator<K> { - val parentIterator = original.iterator() - return object : MutableIterator<K> { - var lastEntry: K? = null - override fun hasNext(): Boolean { - while (lastEntry == null) { - if (!parentIterator.hasNext()) - break - val element = parentIterator.next() - if (!shouldKeepElement(element)) continue - lastEntry = element - } - return lastEntry != null - } - - override fun next(): K { - if (!hasNext()) throw NoSuchElementException() - return lastEntry ?: throw NoSuchElementException() - } - - override fun remove() { - TODO("Not yet implemented") - } - } - } -} - diff --git a/src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt b/src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt deleted file mode 100644 index f7f259d..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/item/NbtItemData.kt +++ /dev/null @@ -1,24 +0,0 @@ - - -package moe.nea.firmament.util.item - -import net.minecraft.component.DataComponentTypes -import net.minecraft.component.type.LoreComponent -import net.minecraft.item.ItemStack -import net.minecraft.text.Text - -var ItemStack.loreAccordingToNbt - get() = get(DataComponentTypes.LORE)?.lines ?: listOf() - set(value) { - set(DataComponentTypes.LORE, LoreComponent(value)) - } - -var ItemStack.displayNameAccordingToNbt: Text - get() = get(DataComponentTypes.CUSTOM_NAME) ?: get(DataComponentTypes.ITEM_NAME) ?: item.name - set(value) { - set(DataComponentTypes.CUSTOM_NAME, value) - } - -fun ItemStack.setCustomName(text: Text) { - set(DataComponentTypes.CUSTOM_NAME, text) -} diff --git a/src/main/kotlin/moe/nea/firmament/util/item/SkullItemData.kt b/src/main/kotlin/moe/nea/firmament/util/item/SkullItemData.kt deleted file mode 100644 index ddab88e..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/item/SkullItemData.kt +++ /dev/null @@ -1,90 +0,0 @@ - - -@file:UseSerializers(DashlessUUIDSerializer::class, InstantAsLongSerializer::class) - -package moe.nea.firmament.util.item - -import com.mojang.authlib.GameProfile -import com.mojang.authlib.minecraft.MinecraftProfileTexture -import com.mojang.authlib.properties.Property -import java.util.UUID -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant -import kotlinx.serialization.Serializable -import kotlinx.serialization.UseSerializers -import kotlinx.serialization.encodeToString -import net.minecraft.component.DataComponentTypes -import net.minecraft.component.type.ProfileComponent -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import moe.nea.firmament.Firmament -import moe.nea.firmament.util.Base64Util.padToValidBase64 -import moe.nea.firmament.util.assertTrueOr -import moe.nea.firmament.util.json.DashlessUUIDSerializer -import moe.nea.firmament.util.json.InstantAsLongSerializer - -@Serializable -data class MinecraftProfileTextureKt( - val url: String, - val metadata: Map<String, String> = mapOf(), -) - -@Serializable -data class MinecraftTexturesPayloadKt( - val textures: Map<MinecraftProfileTexture.Type, MinecraftProfileTextureKt> = mapOf(), - val profileId: UUID? = null, - val profileName: String? = null, - val isPublic: Boolean = true, - val timestamp: Instant = Clock.System.now(), -) - -fun GameProfile.setTextures(textures: MinecraftTexturesPayloadKt) { - val json = Firmament.json.encodeToString(textures) - val encoded = java.util.Base64.getEncoder().encodeToString(json.encodeToByteArray()) - properties.put(propertyTextures, Property(propertyTextures, encoded)) -} - -private val propertyTextures = "textures" - -fun ItemStack.setEncodedSkullOwner(uuid: UUID, encodedData: String) { - assert(this.item == Items.PLAYER_HEAD) - val gameProfile = GameProfile(uuid, "LameGuy123") - gameProfile.properties.put(propertyTextures, Property(propertyTextures, encodedData.padToValidBase64())) - this.set(DataComponentTypes.PROFILE, ProfileComponent(gameProfile)) -} - -val zeroUUID = UUID.fromString("d3cb85e2-3075-48a1-b213-a9bfb62360c1") -fun createSkullItem(uuid: UUID, url: String) = ItemStack(Items.PLAYER_HEAD) - .also { it.setSkullOwner(uuid, url) } - -fun ItemStack.setSkullOwner(uuid: UUID, url: String) { - assert(this.item == Items.PLAYER_HEAD) - val gameProfile = GameProfile(uuid, "nea89") - gameProfile.setTextures( - MinecraftTexturesPayloadKt( - textures = mapOf(MinecraftProfileTexture.Type.SKIN to MinecraftProfileTextureKt(url)), - profileId = uuid, - profileName = "nea89", - ) - ) - this.set(DataComponentTypes.PROFILE, ProfileComponent(gameProfile)) -} - - -fun decodeProfileTextureProperty(property: Property): MinecraftTexturesPayloadKt? { - assertTrueOr(property.name == propertyTextures) { return null } - return try { - var encodedF: String = property.value - while (encodedF.length % 4 != 0 && encodedF.last() == '=') { - encodedF = encodedF.substring(0, encodedF.length - 1) - } - val json = java.util.Base64.getDecoder().decode(encodedF).decodeToString() - Firmament.json.decodeFromString<MinecraftTexturesPayloadKt>(json) - } catch (e: Exception) { - // Malformed profile data - if (Firmament.DEBUG) - e.printStackTrace() - null - } -} - diff --git a/src/main/kotlin/moe/nea/firmament/util/json/BlockPosSerializer.kt b/src/main/kotlin/moe/nea/firmament/util/json/BlockPosSerializer.kt deleted file mode 100644 index 144b0a0..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/json/BlockPosSerializer.kt +++ /dev/null @@ -1,25 +0,0 @@ -package moe.nea.firmament.util.json - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.serializer -import net.minecraft.util.math.BlockPos - -object BlockPosSerializer : KSerializer<BlockPos> { - val delegate = serializer<List<Int>>() - - override val descriptor: SerialDescriptor - get() = SerialDescriptor("BlockPos", delegate.descriptor) - - override fun deserialize(decoder: Decoder): BlockPos { - val list = decoder.decodeSerializableValue(delegate) - require(list.size == 3) - return BlockPos(list[0], list[1], list[2]) - } - - override fun serialize(encoder: Encoder, value: BlockPos) { - encoder.encodeSerializableValue(delegate, listOf(value.x, value.y, value.z)) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/json/DashlessUUIDSerializer.kt b/src/main/kotlin/moe/nea/firmament/util/json/DashlessUUIDSerializer.kt deleted file mode 100644 index acb1dc8..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/json/DashlessUUIDSerializer.kt +++ /dev/null @@ -1,29 +0,0 @@ - - -package moe.nea.firmament.util.json - -import java.util.UUID -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import moe.nea.firmament.util.parseDashlessUUID - -object DashlessUUIDSerializer : KSerializer<UUID> { - override val descriptor: SerialDescriptor = - PrimitiveSerialDescriptor("DashlessUUIDSerializer", PrimitiveKind.STRING) - - override fun deserialize(decoder: Decoder): UUID { - val str = decoder.decodeString() - if ("-" in str) { - return UUID.fromString(str) - } - return parseDashlessUUID(str) - } - - override fun serialize(encoder: Encoder, value: UUID) { - encoder.encodeString(value.toString().replace("-", "")) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/json/InstantAsLongSerializer.kt b/src/main/kotlin/moe/nea/firmament/util/json/InstantAsLongSerializer.kt deleted file mode 100644 index ad738dc..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/json/InstantAsLongSerializer.kt +++ /dev/null @@ -1,22 +0,0 @@ - - -package moe.nea.firmament.util.json - -import kotlinx.datetime.Instant -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder - -object InstantAsLongSerializer : KSerializer<Instant> { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("InstantAsLongSerializer", PrimitiveKind.LONG) - override fun deserialize(decoder: Decoder): Instant { - return Instant.fromEpochMilliseconds(decoder.decodeLong()) - } - - override fun serialize(encoder: Encoder, value: Instant) { - encoder.encodeLong(value.toEpochMilliseconds()) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/json/SingletonSerializableList.kt b/src/main/kotlin/moe/nea/firmament/util/json/SingletonSerializableList.kt deleted file mode 100644 index aa543d6..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/json/SingletonSerializableList.kt +++ /dev/null @@ -1,31 +0,0 @@ - -package moe.nea.firmament.util.json - -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.JsonArray -import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonElement - -class SingletonSerializableList<T>(val child: KSerializer<T>) : KSerializer<List<T>> { - override val descriptor: SerialDescriptor - get() = JsonElement.serializer().descriptor - - override fun deserialize(decoder: Decoder): List<T> { - decoder as JsonDecoder - val list = JsonElement.serializer().deserialize(decoder) - if (list is JsonArray) { - return list.map { - decoder.json.decodeFromJsonElement(child, it) - } - } - return listOf(decoder.json.decodeFromJsonElement(child, list)) - } - - override fun serialize(encoder: Encoder, value: List<T>) { - ListSerializer(child).serialize(encoder, value) - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/listutil.kt b/src/main/kotlin/moe/nea/firmament/util/listutil.kt deleted file mode 100644 index 73cb23e..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/listutil.kt +++ /dev/null @@ -1,9 +0,0 @@ - -package moe.nea.firmament.util - -fun <T, R> List<T>.lastNotNullOfOrNull(func: (T) -> R?): R? { - for (i in indices.reversed()) { - return func(this[i]) ?: continue - } - return null -} diff --git a/src/main/kotlin/moe/nea/firmament/util/propertyutil.kt b/src/main/kotlin/moe/nea/firmament/util/propertyutil.kt deleted file mode 100644 index 795a0d2..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/propertyutil.kt +++ /dev/null @@ -1,9 +0,0 @@ - - -package moe.nea.firmament.util - -import kotlin.properties.ReadOnlyProperty - -fun <T, V, M> ReadOnlyProperty<T, V>.map(mapper: (V) -> M): ReadOnlyProperty<T, M> { - return ReadOnlyProperty { thisRef, property -> mapper(this@map.getValue(thisRef, property)) } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/regex.kt b/src/main/kotlin/moe/nea/firmament/util/regex.kt deleted file mode 100644 index 3ce5bd8..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/regex.kt +++ /dev/null @@ -1,55 +0,0 @@ - - -package moe.nea.firmament.util - -import java.util.regex.Matcher -import java.util.regex.Pattern -import org.intellij.lang.annotations.Language -import kotlin.time.Duration -import kotlin.time.Duration.Companion.minutes -import kotlin.time.Duration.Companion.seconds - -inline fun <T> String.ifMatches(regex: Regex, block: (MatchResult) -> T): T? = - regex.matchEntire(this)?.let(block) - -inline fun <T> Pattern.useMatch(string: String, block: Matcher.() -> T): T? = - matcher(string) - .takeIf(Matcher::matches) - ?.let(block) - -@Language("RegExp") -val TIME_PATTERN = "[0-9]+[ms]" - -@Language("RegExp") -val SHORT_NUMBER_FORMAT = "[0-9]+(?:,[0-9]+)*(?:\\.[0-9]+)?[kKmMbB]?" - - -val siScalars = mapOf( - 'k' to 1_000.0, - 'K' to 1_000.0, - 'm' to 1_000_000.0, - 'M' to 1_000_000.0, - 'b' to 1_000_000_000.0, - 'B' to 1_000_000_000.0, -) - -fun parseTimePattern(text: String): Duration { - val length = text.dropLast(1).toInt() - return when (text.last()) { - 'm' -> length.minutes - 's' -> length.seconds - else -> error("Invalid pattern for time $text") - } -} - -fun parseShortNumber(string: String): Double { - var k = string.replace(",", "") - val scalar = k.last() - var scalarMultiplier = siScalars[scalar] - if (scalarMultiplier == null) { - scalarMultiplier = 1.0 - } else { - k = k.dropLast(1) - } - return k.toDouble() * scalarMultiplier -} diff --git a/src/main/kotlin/moe/nea/firmament/util/render/FacingThePlayerContext.kt b/src/main/kotlin/moe/nea/firmament/util/render/FacingThePlayerContext.kt deleted file mode 100644 index eb37e35..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/render/FacingThePlayerContext.kt +++ /dev/null @@ -1,101 +0,0 @@ - -package moe.nea.firmament.util.render - -import com.mojang.blaze3d.systems.RenderSystem -import io.github.notenoughupdates.moulconfig.platform.next -import org.joml.Matrix4f -import net.minecraft.client.font.TextRenderer -import net.minecraft.client.render.BufferRenderer -import net.minecraft.client.render.GameRenderer -import net.minecraft.client.render.LightmapTextureManager -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexConsumer -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import net.minecraft.util.math.BlockPos -import moe.nea.firmament.util.FirmFormatters -import moe.nea.firmament.util.MC -import moe.nea.firmament.util.assertTrueOr - -@RenderContextDSL -class FacingThePlayerContext(val worldContext: RenderInWorldContext) { - val matrixStack by worldContext::matrixStack - fun waypoint(position: BlockPos, label: Text) { - text( - label, - Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}") - ) - } - - fun text( - vararg texts: Text, - verticalAlign: RenderInWorldContext.VerticalAlign = RenderInWorldContext.VerticalAlign.CENTER, - background: Int = 0x70808080, - ) { - assertTrueOr(texts.isNotEmpty()) { return@text } - for ((index, text) in texts.withIndex()) { - worldContext.matrixStack.push() - val width = MC.font.getWidth(text) - worldContext.matrixStack.translate(-width / 2F, verticalAlign.align(index, texts.size), 0F) - val vertexConsumer: VertexConsumer = - worldContext.vertexConsumers.getBuffer(RenderLayer.getTextBackgroundSeeThrough()) - val matrix4f = worldContext.matrixStack.peek().positionMatrix - vertexConsumer.vertex(matrix4f, -1.0f, -1.0f, 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - vertexConsumer.vertex(matrix4f, -1.0f, MC.font.fontHeight.toFloat(), 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - vertexConsumer.vertex(matrix4f, width.toFloat(), MC.font.fontHeight.toFloat(), 0.0f) - .color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - vertexConsumer.vertex(matrix4f, width.toFloat(), -1.0f, 0.0f).color(background) - .light(LightmapTextureManager.MAX_BLOCK_LIGHT_COORDINATE).next() - worldContext.matrixStack.translate(0F, 0F, 0.01F) - - MC.font.draw( - text, - 0F, - 0F, - -1, - false, - worldContext.matrixStack.peek().positionMatrix, - worldContext.vertexConsumers, - TextRenderer.TextLayerType.SEE_THROUGH, - 0, - LightmapTextureManager.MAX_LIGHT_COORDINATE - ) - worldContext.matrixStack.pop() - } - } - - - fun texture( - texture: Identifier, width: Int, height: Int, - u1: Float, v1: Float, - u2: Float, v2: Float, - ) { - RenderSystem.setShaderTexture(0, texture) - RenderSystem.setShader(GameRenderer::getPositionTexColorProgram) - val hw = width / 2F - val hh = height / 2F - val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix - val buf = Tessellator.getInstance() - .begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR) - buf.vertex(matrix4f, -hw, -hh, 0F) - .color(-1) - .texture(u1, v1).next() - buf.vertex(matrix4f, -hw, +hh, 0F) - .color(-1) - .texture(u1, v2).next() - buf.vertex(matrix4f, +hw, +hh, 0F) - .color(-1) - .texture(u2, v2).next() - buf.vertex(matrix4f, +hw, -hh, 0F) - .color(-1) - .texture(u2, v1).next() - BufferRenderer.drawWithGlobalProgram(buf.end()) - } - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/render/LerpUtils.kt b/src/main/kotlin/moe/nea/firmament/util/render/LerpUtils.kt deleted file mode 100644 index f2c2f25..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/render/LerpUtils.kt +++ /dev/null @@ -1,33 +0,0 @@ - -package moe.nea.firmament.util.render - -import me.shedaniel.math.Color - -val pi = Math.PI -val tau = Math.PI * 2 -fun lerpAngle(a: Float, b: Float, progress: Float): Float { - // TODO: there is at least 10 mods to many in here lol - val shortestAngle = ((((b.mod(tau) - a.mod(tau)).mod(tau)) + tau + pi).mod(tau)) - pi - return ((a + (shortestAngle) * progress).mod(tau)).toFloat() -} - -fun lerp(a: Float, b: Float, progress: Float): Float { - return a + (b - a) * progress -} -fun lerp(a: Int, b: Int, progress: Float): Int { - return (a + (b - a) * progress).toInt() -} - -fun ilerp(a: Float, b: Float, value: Float): Float { - return (value - a) / (b - a) -} - -fun lerp(a: Color, b: Color, progress: Float): Color { - return Color.ofRGBA( - lerp(a.red, b.red, progress), - lerp(a.green, b.green, progress), - lerp(a.blue, b.blue, progress), - lerp(a.alpha, b.alpha, progress), - ) -} - diff --git a/src/main/kotlin/moe/nea/firmament/util/render/RenderCircleProgress.kt b/src/main/kotlin/moe/nea/firmament/util/render/RenderCircleProgress.kt deleted file mode 100644 index a2f42b5..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/render/RenderCircleProgress.kt +++ /dev/null @@ -1,95 +0,0 @@ - -package moe.nea.firmament.util.render - -import com.mojang.blaze3d.systems.RenderSystem -import io.github.notenoughupdates.moulconfig.platform.next -import org.joml.Matrix4f -import org.joml.Vector2f -import kotlin.math.atan2 -import kotlin.math.tan -import net.minecraft.client.gui.DrawContext -import net.minecraft.client.render.BufferRenderer -import net.minecraft.client.render.GameRenderer -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexFormat.DrawMode -import net.minecraft.client.render.VertexFormats -import net.minecraft.util.Identifier - -object RenderCircleProgress { - - fun renderCircle( - drawContext: DrawContext, - texture: Identifier, - progress: Float, - u1: Float, - u2: Float, - v1: Float, - v2: Float, - ) { - RenderSystem.setShaderTexture(0, texture) - RenderSystem.setShader(GameRenderer::getPositionTexColorProgram) - RenderSystem.enableBlend() - val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix - val bufferBuilder = Tessellator.getInstance().begin(DrawMode.TRIANGLES, VertexFormats.POSITION_TEXTURE_COLOR) - - val corners = listOf( - Vector2f(0F, -1F), - Vector2f(1F, -1F), - Vector2f(1F, 0F), - Vector2f(1F, 1F), - Vector2f(0F, 1F), - Vector2f(-1F, 1F), - Vector2f(-1F, 0F), - Vector2f(-1F, -1F), - ) - - for (i in (0 until 8)) { - if (progress < i / 8F) { - break - } - val second = corners[(i + 1) % 8] - val first = corners[i] - if (progress <= (i + 1) / 8F) { - val internalProgress = 1 - (progress - i / 8F) * 8F - val angle = lerpAngle( - atan2(second.y, second.x), - atan2(first.y, first.x), - internalProgress - ) - if (angle < tau / 8 || angle >= tau * 7 / 8) { - second.set(1F, tan(angle)) - } else if (angle < tau * 3 / 8) { - second.set(1 / tan(angle), 1F) - } else if (angle < tau * 5 / 8) { - second.set(-1F, -tan(angle)) - } else { - second.set(-1 / tan(angle), -1F) - } - } - - fun ilerp(f: Float): Float = - ilerp(-1f, 1f, f) - - bufferBuilder - .vertex(matrix, second.x, second.y, 0F) - .texture(lerp(u1, u2, ilerp(second.x)), lerp(v1, v2, ilerp(second.y))) - .color(-1) - .next() - bufferBuilder - .vertex(matrix, first.x, first.y, 0F) - .texture(lerp(u1, u2, ilerp(first.x)), lerp(v1, v2, ilerp(first.y))) - .color(-1) - .next() - bufferBuilder - .vertex(matrix, 0F, 0F, 0F) - .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F))) - .color(-1) - .next() - } - BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()) - RenderSystem.disableBlend() - } - - - -} diff --git a/src/main/kotlin/moe/nea/firmament/util/render/RenderContextDSL.kt b/src/main/kotlin/moe/nea/firmament/util/render/RenderContextDSL.kt deleted file mode 100644 index 9bb4431..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/render/RenderContextDSL.kt +++ /dev/null @@ -1,6 +0,0 @@ - -package moe.nea.firmament.util.render - -@DslMarker -annotation class RenderContextDSL { -} diff --git a/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt b/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt deleted file mode 100644 index 7faa499..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt +++ /dev/null @@ -1,294 +0,0 @@ - - -package moe.nea.firmament.util.render - -import com.mojang.blaze3d.systems.RenderSystem -import io.github.notenoughupdates.moulconfig.platform.next -import java.lang.Math.pow -import org.joml.Matrix4f -import org.joml.Vector3f -import net.minecraft.client.gl.VertexBuffer -import net.minecraft.client.render.BufferBuilder -import net.minecraft.client.render.BufferRenderer -import net.minecraft.client.render.Camera -import net.minecraft.client.render.GameRenderer -import net.minecraft.client.render.RenderLayer -import net.minecraft.client.render.RenderPhase -import net.minecraft.client.render.RenderTickCounter -import net.minecraft.client.render.Tessellator -import net.minecraft.client.render.VertexConsumerProvider -import net.minecraft.client.render.VertexFormat -import net.minecraft.client.render.VertexFormats -import net.minecraft.client.texture.Sprite -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Vec3d -import moe.nea.firmament.events.WorldRenderLastEvent -import moe.nea.firmament.util.FirmFormatters -import moe.nea.firmament.util.MC - -@RenderContextDSL -class RenderInWorldContext private constructor( - private val tesselator: Tessellator, - val matrixStack: MatrixStack, - private val camera: Camera, - private val tickCounter: RenderTickCounter, - val vertexConsumers: VertexConsumerProvider.Immediate, -) { - - object RenderLayers { - val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris", - VertexFormats.POSITION_COLOR, - VertexFormat.DrawMode.TRIANGLES, - RenderLayer.DEFAULT_BUFFER_SIZE, - false, true, - RenderLayer.MultiPhaseParameters.builder() - .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) - .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) - .program(RenderPhase.COLOR_PROGRAM) - .build(false)) - } - - fun color(color: me.shedaniel.math.Color) { - color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f) - } - - fun color(red: Float, green: Float, blue: Float, alpha: Float) { - RenderSystem.setShaderColor(red, green, blue, alpha) - } - - fun block(blockPos: BlockPos) { - matrixStack.push() - matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) - buildCube(matrixStack.peek().positionMatrix, tesselator) - matrixStack.pop() - } - - enum class VerticalAlign { - TOP, BOTTOM, CENTER; - - fun align(index: Int, count: Int): Float { - return when (this) { - CENTER -> (index - count / 2F) * (1 + MC.font.fontHeight.toFloat()) - BOTTOM -> (index - count) * (1 + MC.font.fontHeight.toFloat()) - TOP -> (index) * (1 + MC.font.fontHeight.toFloat()) - } - } - } - - fun waypoint(position: BlockPos, vararg label: Text) { - text( - position.toCenterPos(), - *label, - Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}"), - background = 0xAA202020.toInt() - ) - } - - fun withFacingThePlayer(position: Vec3d, block: FacingThePlayerContext.() -> Unit) { - matrixStack.push() - matrixStack.translate(position.x, position.y, position.z) - val actualCameraDistance = position.distanceTo(camera.pos) - val distanceToMoveTowardsCamera = if (actualCameraDistance < 10) 0.0 else -(actualCameraDistance - 10.0) - val vec = position.subtract(camera.pos).multiply(distanceToMoveTowardsCamera / actualCameraDistance) - matrixStack.translate(vec.x, vec.y, vec.z) - matrixStack.multiply(camera.rotation) - matrixStack.scale(0.025F, -0.025F, 1F) - - FacingThePlayerContext(this).run(block) - - matrixStack.pop() - vertexConsumers.drawCurrentLayer() - } - - fun sprite(position: Vec3d, sprite: Sprite, width: Int, height: Int) { - texture( - position, sprite.atlasId, width, height, sprite.minU, sprite.minV, sprite.maxU, sprite.maxV - ) - } - - fun texture( - position: Vec3d, texture: Identifier, width: Int, height: Int, - u1: Float, v1: Float, - u2: Float, v2: Float, - ) { - withFacingThePlayer(position) { - texture(texture, width, height, u1, v1, u2, v2) - } - } - - fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER, background: Int = 0x70808080) { - withFacingThePlayer(position) { - text(*texts, verticalAlign = verticalAlign, background = background) - } - } - - fun tinyBlock(vec3d: Vec3d, size: Float) { - RenderSystem.setShader(GameRenderer::getPositionColorProgram) - matrixStack.push() - matrixStack.translate(vec3d.x, vec3d.y, vec3d.z) - matrixStack.scale(size, size, size) - matrixStack.translate(-.5, -.5, -.5) - buildCube(matrixStack.peek().positionMatrix, tesselator) - matrixStack.pop() - } - - fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) { - RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) - matrixStack.push() - RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat()) - matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) - buildWireFrameCube(matrixStack.peek(), tesselator) - matrixStack.pop() - } - - fun line(vararg points: Vec3d, lineWidth: Float = 10F) { - line(points.toList(), lineWidth) - } - - fun tracer(toWhere: Vec3d, lineWidth: Float = 3f) { - val cameraForward = Vector3f(0f, 0f, 1f).rotate(camera.rotation) - line(camera.pos.add(Vec3d(cameraForward)), toWhere, lineWidth = lineWidth) - } - - fun line(points: List<Vec3d>, lineWidth: Float = 10F) { - RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) - RenderSystem.lineWidth(lineWidth) - val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) - - val matrix = matrixStack.peek() - var lastNormal: Vector3f? = null - points.zipWithNext().forEach { (a, b) -> - val normal = Vector3f(b.x.toFloat(), b.y.toFloat(), b.z.toFloat()) - .sub(a.x.toFloat(), a.y.toFloat(), a.z.toFloat()) - .normalize() - val lastNormal0 = lastNormal ?: normal - lastNormal = normal - buffer.vertex(matrix.positionMatrix, a.x.toFloat(), a.y.toFloat(), a.z.toFloat()) - .color(-1) - .normal(matrix, lastNormal0.x, lastNormal0.y, lastNormal0.z) - .next() - buffer.vertex(matrix.positionMatrix, b.x.toFloat(), b.y.toFloat(), b.z.toFloat()) - .color(-1) - .normal(matrix, normal.x, normal.y, normal.z) - .next() - } - - BufferRenderer.drawWithGlobalProgram(buffer.end()) - } - - companion object { - private fun doLine( - matrix: MatrixStack.Entry, - buf: BufferBuilder, - i: Float, - j: Float, - k: Float, - x: Float, - y: Float, - z: Float - ) { - val normal = Vector3f(x, y, z) - .sub(i, j, k) - .normalize() - buf.vertex(matrix.positionMatrix, i, j, k) - .normal(matrix, normal.x, normal.y, normal.z) - .color(-1) - .next() - buf.vertex(matrix.positionMatrix, x, y, z) - .normal(matrix, normal.x, normal.y, normal.z) - .color(-1) - .next() - } - - - private fun buildWireFrameCube(matrix: MatrixStack.Entry, tessellator: Tessellator) { - val buf = tessellator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) - - for (i in 0..1) { - for (j in 0..1) { - val i = i.toFloat() - val j = j.toFloat() - doLine(matrix, buf, 0F, i, j, 1F, i, j) - doLine(matrix, buf, i, 0F, j, i, 1F, j) - doLine(matrix, buf, i, j, 0F, i, j, 1F) - } - } - BufferRenderer.drawWithGlobalProgram(buf.end()) - } - - private fun buildCube(matrix: Matrix4f, tessellator: Tessellator) { - val buf = tessellator.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR) - buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() - buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() - RenderLayers.TRANSLUCENT_TRIS.draw(buf.end()) - } - - - fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) { - RenderSystem.disableDepthTest() - RenderSystem.enableBlend() - RenderSystem.defaultBlendFunc() - RenderSystem.disableCull() - - event.matrices.push() - event.matrices.translate(-event.camera.pos.x, -event.camera.pos.y, -event.camera.pos.z) - - val ctx = RenderInWorldContext( - RenderSystem.renderThreadTesselator(), - event.matrices, - event.camera, - event.tickCounter, - event.vertexConsumers - ) - - block(ctx) - - event.matrices.pop() - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F) - VertexBuffer.unbind() - RenderSystem.enableDepthTest() - RenderSystem.enableCull() - RenderSystem.disableBlend() - } - } -} - - diff --git a/src/main/kotlin/moe/nea/firmament/util/render/TranslatedScissors.kt b/src/main/kotlin/moe/nea/firmament/util/render/TranslatedScissors.kt deleted file mode 100644 index c1e6544..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/render/TranslatedScissors.kt +++ /dev/null @@ -1,22 +0,0 @@ - -package moe.nea.firmament.util.render - -import org.joml.Vector4f -import net.minecraft.client.gui.DrawContext - -fun DrawContext.enableScissorWithTranslation(x1: Float, y1: Float, x2: Float, y2: Float) { - val pMat = matrices.peek().positionMatrix - val target = Vector4f() - - target.set(x1, y1, 0f, 1f) - target.mul(pMat) - val scissorX1 = target.x - val scissorY1 = target.y - - target.set(x2, y2, 0f, 1f) - target.mul(pMat) - val scissorX2 = target.x - val scissorY2 = target.y - - enableScissor(scissorX1.toInt(), scissorY1.toInt(), scissorX2.toInt(), scissorY2.toInt()) -} diff --git a/src/main/kotlin/moe/nea/firmament/util/stringutil.kt b/src/main/kotlin/moe/nea/firmament/util/stringutil.kt deleted file mode 100644 index 56f8dbe..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/stringutil.kt +++ /dev/null @@ -1,6 +0,0 @@ - -package moe.nea.firmament.util - -fun parseIntWithComma(string: String): Int { - return string.replace(",", "").toInt() -} diff --git a/src/main/kotlin/moe/nea/firmament/util/textutil.kt b/src/main/kotlin/moe/nea/firmament/util/textutil.kt deleted file mode 100644 index a05733c..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/textutil.kt +++ /dev/null @@ -1,117 +0,0 @@ - - -package moe.nea.firmament.util - -import net.minecraft.text.MutableText -import net.minecraft.text.PlainTextContent -import net.minecraft.text.Style -import net.minecraft.text.Text -import net.minecraft.text.TranslatableTextContent -import net.minecraft.util.Formatting -import moe.nea.firmament.Firmament - - -class TextMatcher(text: Text) { - data class State( - var iterator: MutableList<Text>, - var currentText: Text?, - var offset: Int, - var textContent: String, - ) - - var state = State( - mutableListOf(text), - null, - 0, - "" - ) - - fun pollChunk(): Boolean { - val firstOrNull = state.iterator.removeFirstOrNull() ?: return false - state.offset = 0 - state.currentText = firstOrNull - state.textContent = when (val content = firstOrNull.content) { - is PlainTextContent.Literal -> content.string - else -> { - Firmament.logger.warn("TextContent of type ${content.javaClass} not understood.") - return false - } - } - state.iterator.addAll(0, firstOrNull.siblings) - return true - } - - fun pollChunks(): Boolean { - while (state.offset !in state.textContent.indices) { - if (!pollChunk()) { - return false - } - } - return true - } - - fun pollChar(): Char? { - if (!pollChunks()) return null - return state.textContent[state.offset++] - } - - - fun expectString(string: String): Boolean { - var found = "" - while (found.length < string.length) { - if (!pollChunks()) return false - val takeable = state.textContent.drop(state.offset).take(string.length - found.length) - state.offset += takeable.length - found += takeable - } - return found == string - } -} - -val formattingChars = "kmolnrKMOLNR".toSet() -fun CharSequence.removeColorCodes(keepNonColorCodes: Boolean = false): String { - var nextParagraph = indexOf('§') - if (nextParagraph < 0) return this.toString() - val stringBuffer = StringBuilder(this.length) - var readIndex = 0 - while (nextParagraph >= 0) { - stringBuffer.append(this, readIndex, nextParagraph) - if (keepNonColorCodes && nextParagraph + 1 < length && this[nextParagraph + 1] in formattingChars) { - readIndex = nextParagraph - nextParagraph = indexOf('§', startIndex = readIndex + 1) - } else { - readIndex = nextParagraph + 2 - nextParagraph = indexOf('§', startIndex = readIndex) - } - if (readIndex > this.length) - readIndex = this.length - } - stringBuffer.append(this, readIndex, this.length) - return stringBuffer.toString() -} - -val Text.unformattedString: String - get() = string.removeColorCodes() - - -fun MutableText.withColor(formatting: Formatting) = this.styled { it.withColor(formatting).withItalic(false) } - -fun Text.transformEachRecursively(function: (Text) -> Text): Text { - val c = this.content - if (c is TranslatableTextContent) { - return Text.translatableWithFallback(c.key, c.fallback, *c.args.map { - (if (it is Text) it else Text.literal(it.toString())).transformEachRecursively(function) - }.toTypedArray()).also { new -> - new.style = this.style - new.siblings.clear() - this.siblings.forEach { child -> - new.siblings.add(child.transformEachRecursively(function)) - } - } - } - return function(this.copy().also { it.siblings.clear() }).also { tt -> - this.siblings.forEach { - tt.siblings.add(it.transformEachRecursively(function)) - } - } -} diff --git a/src/main/kotlin/moe/nea/firmament/util/uuid.kt b/src/main/kotlin/moe/nea/firmament/util/uuid.kt deleted file mode 100644 index 4aa0749..0000000 --- a/src/main/kotlin/moe/nea/firmament/util/uuid.kt +++ /dev/null @@ -1,12 +0,0 @@ - - -package moe.nea.firmament.util - -import java.math.BigInteger -import java.util.UUID - -fun parseDashlessUUID(dashlessUuid: String): UUID { - val most = BigInteger(dashlessUuid.substring(0, 16), 16) - val least = BigInteger(dashlessUuid.substring(16, 32), 16) - return UUID(most.toLong(), least.toLong()) -} |