From c38dcee2c5f483ef5990ae9204355e1bc3c2bf74 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Mon, 28 Oct 2024 12:07:55 +0100 Subject: Make REI optional --- build.gradle.kts | 6 +- gradle/libs.versions.toml | 4 + .../moe/nea/firmament/compat/rei/EntityWidget.kt | 35 +++ .../nea/firmament/compat/rei/FirmamentReiPlugin.kt | 143 ++++++++++++ .../compat/rei/HoveredItemStackProvider.kt | 37 +++ .../firmament/compat/rei/NEUItemEntryRenderer.kt | 187 +++++++++++++++ .../firmament/compat/rei/NEUItemEntrySerializer.kt | 30 +++ .../firmament/compat/rei/SBItemEntryDefinition.kt | 94 ++++++++ .../rei/SkyblockCraftingRecipeDynamicGenerator.kt | 65 ++++++ .../rei/SkyblockItemIdFocusedStackProvider.kt | 25 ++ .../rei/java/moe/nea/firmament/compat/rei/math.kt | 10 + .../compat/rei/recipes/SBCraftingRecipe.kt | 55 +++++ .../compat/rei/recipes/SBEssenceUpgradeRecipe.kt | 62 +++++ .../firmament/compat/rei/recipes/SBForgeRecipe.kt | 71 ++++++ .../firmament/compat/rei/recipes/SBKatRecipe.kt | 224 ++++++++++++++++++ .../compat/rei/recipes/SBMobDropRecipe.kt | 108 +++++++++ .../nea/firmament/compat/rei/recipes/SBRecipe.kt | 29 +++ .../events/anniversity/AnniversaryFeatures.kt | 8 +- .../kotlin/features/inventory/CraftingOverlay.kt | 20 +- src/main/kotlin/gui/entity/EntityWidget.kt | 35 --- src/main/kotlin/gui/entity/ModifyEquipment.kt | 70 +++--- src/main/kotlin/rei/FirmamentReiPlugin.kt | 142 ------------ src/main/kotlin/rei/NEUItemEntryRenderer.kt | 186 --------------- src/main/kotlin/rei/NEUItemEntrySerializer.kt | 29 --- src/main/kotlin/rei/SBItemEntryDefinition.kt | 254 --------------------- .../rei/SkyblockCraftingRecipeDynamicGenerator.kt | 64 ------ .../rei/SkyblockItemIdFocusedStackProvider.kt | 25 -- src/main/kotlin/rei/math.kt | 10 - src/main/kotlin/rei/recipes/SBCraftingRecipe.kt | 55 ----- .../kotlin/rei/recipes/SBEssenceUpgradeRecipe.kt | 62 ----- src/main/kotlin/rei/recipes/SBForgeRecipe.kt | 71 ------ src/main/kotlin/rei/recipes/SBKatRecipe.kt | 224 ------------------ src/main/kotlin/rei/recipes/SBMobDropRecipe.kt | 108 --------- src/main/kotlin/rei/recipes/SBRecipe.kt | 31 --- src/main/kotlin/repo/PetData.kt | 24 ++ src/main/kotlin/repo/RepoManager.kt | 5 +- src/main/kotlin/repo/SBItemStack.kt | 165 +++++++++++++ src/main/kotlin/util/HoveredItemStack.kt | 42 ++-- src/main/kotlin/util/SkyblockId.kt | 5 +- src/main/kotlin/util/compatloader/CompatLoader.kt | 3 + src/main/resources/fabric.mod.json | 2 +- 41 files changed, 1451 insertions(+), 1374 deletions(-) create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/HoveredItemStackProvider.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntrySerializer.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockCraftingRecipeDynamicGenerator.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockItemIdFocusedStackProvider.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/math.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBCraftingRecipe.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBEssenceUpgradeRecipe.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBForgeRecipe.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBKatRecipe.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt create mode 100644 src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBRecipe.kt delete mode 100644 src/main/kotlin/gui/entity/EntityWidget.kt delete mode 100644 src/main/kotlin/rei/FirmamentReiPlugin.kt delete mode 100644 src/main/kotlin/rei/NEUItemEntryRenderer.kt delete mode 100644 src/main/kotlin/rei/NEUItemEntrySerializer.kt delete mode 100644 src/main/kotlin/rei/SBItemEntryDefinition.kt delete mode 100644 src/main/kotlin/rei/SkyblockCraftingRecipeDynamicGenerator.kt delete mode 100644 src/main/kotlin/rei/SkyblockItemIdFocusedStackProvider.kt delete mode 100644 src/main/kotlin/rei/math.kt delete mode 100644 src/main/kotlin/rei/recipes/SBCraftingRecipe.kt delete mode 100644 src/main/kotlin/rei/recipes/SBEssenceUpgradeRecipe.kt delete mode 100644 src/main/kotlin/rei/recipes/SBForgeRecipe.kt delete mode 100644 src/main/kotlin/rei/recipes/SBKatRecipe.kt delete mode 100644 src/main/kotlin/rei/recipes/SBMobDropRecipe.kt delete mode 100644 src/main/kotlin/rei/recipes/SBRecipe.kt create mode 100644 src/main/kotlin/repo/PetData.kt create mode 100644 src/main/kotlin/repo/SBItemStack.kt diff --git a/build.gradle.kts b/build.gradle.kts index 244b01d..4bcffe8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -185,6 +185,7 @@ val yaclSourceSet = createIsolatedSourceSet("yacl") val explosiveEnhancementSourceSet = createIsolatedSourceSet("explosiveEnhancement") val wildfireGenderSourceSet = createIsolatedSourceSet("wildfireGender") val modmenuSourceSet = createIsolatedSourceSet("modmenu") +val reiSourceSet = createIsolatedSourceSet("rei") dependencies { // Minecraft dependencies @@ -199,6 +200,8 @@ dependencies { modImplementation(libs.fabric.kotlin) modImplementation(libs.moulconfig) modImplementation(libs.manninghamMills) + modImplementation(libs.basicMath) + include(libs.basicMath) (modmenuSourceSet.modImplementationConfigurationName)(libs.modmenu) (explosiveEnhancementSourceSet.modImplementationConfigurationName)(libs.explosiveenhancement) modImplementation(libs.hypixelmodapi) @@ -234,13 +237,14 @@ dependencies { (yaclSourceSet.modImplementationConfigurationName)(libs.yacl) // Actual dependencies - modCompileOnly(libs.rei.api) { + (reiSourceSet.modImplementationConfigurationName)(libs.rei.api) { exclude(module = "architectury") exclude(module = "architectury-fabric") } nonModImplentation(libs.repoparser) shadowMe(libs.repoparser) fun ktor(mod: String) = "io.ktor:ktor-$mod-jvm:${libs.versions.ktor.get()}" + // TODO: get rid of ktor. lowkey ballooning file size and like not neccessary at all for what i am doing.0 transInclude(nonModImplentation(ktor("client-core"))!!) transInclude(nonModImplentation(ktor("client-java"))!!) transInclude(nonModImplentation(ktor("serialization-kotlinx-json"))!!) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index efb7c94..62a7a13 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -79,6 +79,9 @@ manninghamMills = "2.4.1" # Update from https://docs.isxander.dev/yet-another-config-lib/installing-yacl yacl = "3.5.0+1.21-fabric" +# Update from https://maven.shedaniel.me/me/shedaniel/cloth/basic-math/0.6.1/ +basicMath = "0.6.1" + [libraries] minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } fabric_loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric_loader" } @@ -113,6 +116,7 @@ freecammod = { module = "maven.modrinth:freecam", version.ref = "freecammod" } citresewn = { module = "maven.modrinth:cit-resewn", version.ref = "citresewn" } femalegender = { module = "maven.modrinth:female-gender", version.ref = "femalegender" } yacl = { module = "dev.isxander:yet-another-config-lib", version.ref = "yacl" } +basicMath = { module = "me.shedaniel.cloth:basic-math", version.ref = "basicMath" } [bundles] runtime_required = [ diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt new file mode 100644 index 0000000..9b7b190 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt @@ -0,0 +1,35 @@ +package moe.nea.firmament.compat.rei + +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 moe.nea.firmament.gui.entity.EntityRenderer +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 { + 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/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt new file mode 100644 index 0000000..d95d2d1 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt @@ -0,0 +1,143 @@ +package moe.nea.firmament.compat.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.compat.rei.recipes.SBCraftingRecipe +import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe +import moe.nea.firmament.compat.rei.recipes.SBForgeRecipe +import moe.nea.firmament.compat.rei.recipes.SBKatRecipe +import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe +import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.repo.SBItemStack +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.ScreenUtil +import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.guessRecipeId +import moe.nea.firmament.util.skyblockId +import moe.nea.firmament.util.unformattedString + + +class FirmamentReiPlugin : REIClientPlugin { + + companion object { + fun EntryStack.asItemEntry(): EntryStack { + 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) return@TransferHandler TransferHandler.Result.createNotApplicable() + val neuItem = RepoManager.getNEUItem(SkyblockId(display.neuRecipe.output.itemId)) + ?: error("Could not find neu item ${display.neuRecipe.output.itemId} which is used in a recipe output") + val useSuperCraft = context.isStackedCrafting || RepoManager.Config.alwaysSuperCraft + if (neuItem.isVanilla && useSuperCraft) return@TransferHandler TransferHandler.Result.createFailed(Text.translatable( + "firmament.recipe.novanilla")) + var shouldReturn = true + if (context.isActuallyCrafting && !useSuperCraft) { + if (screen !is GenericContainerScreen || screen.title?.unformattedString != CraftingOverlay.CRAFTING_SCREEN_NAME) { + MC.sendCommand("craft") + shouldReturn = false + } + CraftingOverlay.setOverlay(screen as? GenericContainerScreen, display.neuRecipe) + } + if (context.isActuallyCrafting && useSuperCraft) { + shouldReturn = false + MC.sendCommand("viewrecipe ${neuItem.guessRecipeId()}") + } + return@TransferHandler TransferHandler.Result.createSuccessful().blocksFurtherHandling(shouldReturn) + }) + } + + 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 isHandingScreen(screen: Class?): Boolean { + return screen == StorageOverlayScreen::class.java + } + + override fun 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/compat/rei/java/moe/nea/firmament/compat/rei/HoveredItemStackProvider.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/HoveredItemStackProvider.kt new file mode 100644 index 0000000..3d21b66 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/HoveredItemStackProvider.kt @@ -0,0 +1,37 @@ +package moe.nea.firmament.compat.rei + +import com.google.auto.service.AutoService +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.util.HoveredItemStackProvider +import moe.nea.firmament.util.compatloader.CompatLoader + +@AutoService(HoveredItemStackProvider::class) +@CompatLoader.RequireMod("roughlyenoughitems") +class ScreenRegistryHoveredItemStackProvider : HoveredItemStackProvider { + override fun provideHoveredItemStack(screen: HandledScreen<*>): ItemStack? { + val entryStack = ScreenRegistry.getInstance().getFocusedStack(screen, PointHelper.ofMouse()) + ?: return null + return entryStack.value as? ItemStack ?: entryStack.cheatsAs().value + } +} +@AutoService(HoveredItemStackProvider::class) +@CompatLoader.RequireMod("roughlyenoughitems") +class OverlayHoveredItemStackProvider : HoveredItemStackProvider { + override fun provideHoveredItemStack(screen: HandledScreen<*>): ItemStack? { + 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/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt new file mode 100644 index 0000000..a02742b --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt @@ -0,0 +1,187 @@ +/* + * SPDX-FileCopyrightText: 2018-2023 shedaniel + * SPDX-FileCopyrightText: 2023 Linnea Gräf + * SPDX-FileCopyrightText: 2024 Linnea Gräf + * + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-License-Identifier: MIT + */ + +package moe.nea.firmament.compat.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.compat.rei.FirmamentReiPlugin.Companion.asItemEntry +import moe.nea.firmament.repo.SBItemStack + +object NEUItemEntryRenderer : EntryRenderer, BatchedEntryRenderer { + override fun render( + entry: EntryStack, + 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, 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): BakedModel { + return minecraft.itemRenderer.getModel(entry.asItemEntry().value, minecraft.world, minecraft.player, 0) + } + + override fun getBatchIdentifier(entry: EntryStack?, bounds: Rectangle?, extraData: BakedModel): Int { + return 1738923 + if (extraData.isSideLit) 1 else 0 + } + + override fun startBatch( + entry: EntryStack, + 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, + 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, + 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, + 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) { + if (!entry.isEmpty) { + graphics.drawItemInSlot(MinecraftClient.getInstance().textRenderer, entry.value, 0, 0, null) + } + } + + override fun endBatch( + entry: EntryStack?, + extraData: BakedModel?, + graphics: DrawContext?, + delta: Float + ) { + } + +} diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntrySerializer.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntrySerializer.kt new file mode 100644 index 0000000..6a03a48 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntrySerializer.kt @@ -0,0 +1,30 @@ + + +package moe.nea.firmament.compat.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.repo.SBItemStack +import moe.nea.firmament.util.SkyblockId + +object NEUItemEntrySerializer : EntrySerializer { + 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, value: SBItemStack): NbtCompound { + return NbtCompound().apply { + putString(SKYBLOCK_ID_ENTRY, value.skyblockId.neuItem) + putInt(SKYBLOCK_ITEM_COUNT, value.getStackSize()) + } + } +} diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt new file mode 100644 index 0000000..a242c1b --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt @@ -0,0 +1,94 @@ +package moe.nea.firmament.compat.rei + +import io.github.moulberry.repo.data.NEUIngredient +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.Identifier +import moe.nea.firmament.compat.rei.FirmamentReiPlugin.Companion.asItemEntry +import moe.nea.firmament.repo.PetData +import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.repo.SBItemStack +import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.petData +import moe.nea.firmament.util.skyBlockId + +object SBItemEntryDefinition : EntryDefinition { + override fun equals(o1: SBItemStack, o2: SBItemStack, context: ComparisonContext): Boolean { + return o1.skyblockId == o2.skyblockId && o1.getStackSize() == o2.getStackSize() + } + + override fun cheatsAs(entry: EntryStack?, value: SBItemStack): ItemStack { + return value.asCopiedItemStack() + } + + override fun getValueType(): Class = SBItemStack::class.java + override fun getType(): EntryType = EntryType.deferred(FirmamentReiPlugin.SKYBLOCK_ITEM_TYPE_ID) + + override fun getRenderer(): EntryRenderer = NEUItemEntryRenderer + + override fun getSerializer(): EntrySerializer { + return NEUItemEntrySerializer + } + + override fun getTagsFor(entry: EntryStack?, value: SBItemStack?): Stream>? { + return Stream.empty() + } + + override fun asFormattedText(entry: EntryStack, value: SBItemStack): Text { + return VanillaEntryTypes.ITEM.definition.asFormattedText(entry.asItemEntry(), value.asImmutableItemStack()) + } + + override fun hash(entry: EntryStack, 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?, value: SBItemStack): SBItemStack { + return value.copy(stackSize = 1, petData = RepoManager.getPotentialStubPetData(value.skyblockId), + stars = 0, extraLore = listOf()) + } + + override fun normalize(entry: EntryStack?, value: SBItemStack): SBItemStack { + return wildcard(entry, value) + } + + override fun copy(entry: EntryStack?, value: SBItemStack): SBItemStack { + return value + } + + override fun isEmpty(entry: EntryStack?, value: SBItemStack): Boolean { + return value.getStackSize() == 0 + } + + override fun getIdentifier(entry: EntryStack?, value: SBItemStack): Identifier { + return value.skyblockId.identifier + } + + fun getEntry(sbItemStack: SBItemStack): EntryStack = + EntryStack.of(this, sbItemStack) + + fun getEntry(skyblockId: SkyblockId, count: Int = 1): EntryStack = + getEntry(SBItemStack(skyblockId, count)) + + fun getEntry(ingredient: NEUIngredient): EntryStack = + getEntry(SkyblockId(ingredient.itemId), count = ingredient.amount.toInt()) + + fun getEntry(stack: ItemStack): EntryStack = + 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/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockCraftingRecipeDynamicGenerator.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockCraftingRecipeDynamicGenerator.kt new file mode 100644 index 0000000..f52f418 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockCraftingRecipeDynamicGenerator.kt @@ -0,0 +1,65 @@ + + +package moe.nea.firmament.compat.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.compat.rei.recipes.SBCraftingRecipe +import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe +import moe.nea.firmament.compat.rei.recipes.SBForgeRecipe +import moe.nea.firmament.compat.rei.recipes.SBKatRecipe +import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe +import moe.nea.firmament.repo.EssenceRecipeProvider +import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.repo.SBItemStack + + +val SkyblockCraftingRecipeDynamicGenerator = + neuDisplayGenerator { SBCraftingRecipe(it) } + +val SkyblockForgeRecipeDynamicGenerator = + neuDisplayGenerator { SBForgeRecipe(it) } + +val SkyblockMobDropRecipeDynamicGenerator = + neuDisplayGenerator { SBMobDropRecipe(it) } + +val SkyblockKatRecipeDynamicGenerator = + neuDisplayGenerator { SBKatRecipe(it) } +val SkyblockEssenceRecipeDynamicGenerator = + neuDisplayGenerator { SBEssenceUpgradeRecipe(it) } + +inline fun neuDisplayGenerator(crossinline mapper: (T) -> D) = + object : DynamicDisplayGenerator { + override fun getRecipeFor(entry: EntryStack<*>): Optional> { + if (entry.type != SBItemEntryDefinition.type) return Optional.empty() + val item = entry.castValue() + val recipes = RepoManager.getRecipesFor(item.skyblockId) + val craftingRecipes = recipes.filterIsInstance() + return Optional.of(craftingRecipes.map(mapper)) + } + + override fun generate(builder: ViewSearchBuilder): Optional> { + if (SBCraftingRecipe.Category.catIdentifier !in builder.categories) return Optional.empty() + return Optional.of( + RepoManager.getAllRecipes().filterIsInstance().map { mapper(it) } + .toList() + ) + } + + override fun getUsageFor(entry: EntryStack<*>): Optional> { + if (entry.type != SBItemEntryDefinition.type) return Optional.empty() + val item = entry.castValue() + val recipes = RepoManager.getUsagesFor(item.skyblockId) + val craftingRecipes = recipes.filterIsInstance() + return Optional.of(craftingRecipes.map(mapper)) + + } + } diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockItemIdFocusedStackProvider.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockItemIdFocusedStackProvider.kt new file mode 100644 index 0000000..cfb6f74 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/SkyblockItemIdFocusedStackProvider.kt @@ -0,0 +1,25 @@ + + +package moe.nea.firmament.compat.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> { + 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/compat/rei/java/moe/nea/firmament/compat/rei/math.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/math.kt new file mode 100644 index 0000000..7db36f2 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/math.kt @@ -0,0 +1,10 @@ + + +package moe.nea.firmament.compat.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/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBCraftingRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBCraftingRecipe.kt new file mode 100644 index 0000000..ed18c6e --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBCraftingRecipe.kt @@ -0,0 +1,55 @@ + + +package moe.nea.firmament.compat.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.compat.rei.SBItemEntryDefinition + +class SBCraftingRecipe(override val neuRecipe: NEUCraftingRecipe) : SBRecipe() { + override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.catIdentifier + + object Category : DisplayCategory { + val catIdentifier = CategoryIdentifier.of(Firmament.MOD_ID, "crafing_recipe") + override fun getCategoryIdentifier(): CategoryIdentifier = 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 { + 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/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBEssenceUpgradeRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBEssenceUpgradeRecipe.kt new file mode 100644 index 0000000..f81d529 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBEssenceUpgradeRecipe.kt @@ -0,0 +1,62 @@ + +package moe.nea.firmament.compat.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.compat.rei.SBItemEntryDefinition +import moe.nea.firmament.repo.EssenceRecipeProvider +import moe.nea.firmament.repo.SBItemStack +import moe.nea.firmament.util.SkyblockId + +class SBEssenceUpgradeRecipe(override val neuRecipe: EssenceRecipeProvider.EssenceUpgradeRecipe) : SBRecipe() { + object Category : DisplayCategory { + override fun getCategoryIdentifier(): CategoryIdentifier = + 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 { + val recipe = display.neuRecipe + val list = mutableListOf() + 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/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBForgeRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBForgeRecipe.kt new file mode 100644 index 0000000..bb51021 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBForgeRecipe.kt @@ -0,0 +1,71 @@ + + +package moe.nea.firmament.compat.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.compat.rei.SBItemEntryDefinition +import moe.nea.firmament.compat.rei.plus + +class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() { + override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier + + object Category : DisplayCategory { + override fun getCategoryIdentifier(): CategoryIdentifier = + 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 { + 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/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBKatRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBKatRecipe.kt new file mode 100644 index 0000000..fc77fa6 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBKatRecipe.kt @@ -0,0 +1,224 @@ + +package moe.nea.firmament.compat.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.compat.rei.SBItemEntryDefinition +import moe.nea.firmament.repo.PetData +import moe.nea.firmament.repo.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 { + override fun getCategoryIdentifier(): CategoryIdentifier = + 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 { + 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 { + 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/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt new file mode 100644 index 0000000..cb240fc --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt @@ -0,0 +1,108 @@ + +package moe.nea.firmament.compat.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.compat.rei.EntityWidget +import moe.nea.firmament.compat.rei.SBItemEntryDefinition + +class SBMobDropRecipe(override val neuRecipe: NEUMobDropRecipe) : SBRecipe() { + override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier + + object Category : DisplayCategory { + override fun getCategoryIdentifier(): CategoryIdentifier = + 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 { + 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() + 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/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBRecipe.kt new file mode 100644 index 0000000..a66a529 --- /dev/null +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBRecipe.kt @@ -0,0 +1,29 @@ +package moe.nea.firmament.compat.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.compat.rei.SBItemEntryDefinition +import moe.nea.firmament.util.SkyblockId + +abstract class SBRecipe : Display { + abstract val neuRecipe: NEURecipe + override fun getInputEntries(): List { + 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 { + 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/features/events/anniversity/AnniversaryFeatures.kt b/src/main/kotlin/features/events/anniversity/AnniversaryFeatures.kt index 825cd6c..5151862 100644 --- a/src/main/kotlin/features/events/anniversity/AnniversaryFeatures.kt +++ b/src/main/kotlin/features/events/anniversity/AnniversaryFeatures.kt @@ -15,8 +15,8 @@ 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.repo.SBItemStack import moe.nea.firmament.util.MC import moe.nea.firmament.util.SHORT_NUMBER_FORMAT import moe.nea.firmament.util.SkyblockId @@ -197,9 +197,9 @@ object AnniversaryFeatures : FirmamentFeature { } val itemStack = if (backedBy is Reward.Items) { - SBItemEntryDefinition.getEntry(backedBy.item, backedBy.amount) + SBItemStack(backedBy.item, backedBy.amount) } else { - SBItemEntryDefinition.getEntry(SkyblockId.NULL) + SBItemStack(SkyblockId.NULL) } @Bind @@ -207,7 +207,7 @@ object AnniversaryFeatures : FirmamentFeature { return when (backedBy) { is Reward.Coins -> "Coins" is Reward.EXP -> backedBy.skill - is Reward.Items -> itemStack.value.asItemStack().name.string + is Reward.Items -> itemStack.asImmutableItemStack().name.string is Reward.Unknown -> backedBy.text } } diff --git a/src/main/kotlin/features/inventory/CraftingOverlay.kt b/src/main/kotlin/features/inventory/CraftingOverlay.kt index 8e75478..a958e25 100644 --- a/src/main/kotlin/features/inventory/CraftingOverlay.kt +++ b/src/main/kotlin/features/inventory/CraftingOverlay.kt @@ -1,5 +1,6 @@ package moe.nea.firmament.features.inventory +import io.github.moulberry.repo.data.NEUCraftingRecipe import net.minecraft.client.gui.screen.ingame.GenericContainerScreen import net.minecraft.item.ItemStack import net.minecraft.util.Formatting @@ -7,15 +8,14 @@ import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ScreenChangeEvent 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.repo.SBItemStack import moe.nea.firmament.util.MC +import moe.nea.firmament.util.skyblockId object CraftingOverlay : FirmamentFeature { private var screen: GenericContainerScreen? = null - private var recipe: SBCraftingRecipe? = null + private var recipe: NEUCraftingRecipe? = null private var useNextScreen = false private val craftingOverlayIndices = listOf( 10, 11, 12, @@ -24,7 +24,7 @@ object CraftingOverlay : FirmamentFeature { ) val CRAFTING_SCREEN_NAME = "Craft Item" - fun setOverlay(screen: GenericContainerScreen?, recipe: SBCraftingRecipe) { + fun setOverlay(screen: GenericContainerScreen?, recipe: NEUCraftingRecipe) { this.screen = screen if (screen == null) { useNextScreen = true @@ -52,10 +52,12 @@ object CraftingOverlay : FirmamentFeature { if (slot.inventory != screen?.screenHandler?.inventory) return val recipeIndex = craftingOverlayIndices.indexOf(slot.index) if (recipeIndex < 0) return - val expectedItem = recipe.neuRecipe.inputs[recipeIndex] + val expectedItem = recipe.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) { + val actualEntry = SBItemStack(actualStack) + if ((actualEntry.skyblockId != expectedItem.skyblockId || actualEntry.getStackSize() < expectedItem.amount) + && expectedItem.amount.toInt() != 0 + ) { event.context.fill( event.slot.x, event.slot.y, @@ -65,7 +67,7 @@ object CraftingOverlay : FirmamentFeature { ) } if (!slot.hasStack()) { - val itemStack = SBItemEntryDefinition.getEntry(expectedItem).asItemEntry().value + val itemStack = SBItemStack(expectedItem)?.asImmutableItemStack() ?: return event.context.drawItem(itemStack, event.slot.x, event.slot.y) event.context.drawItemInSlot( MC.font, diff --git a/src/main/kotlin/gui/entity/EntityWidget.kt b/src/main/kotlin/gui/entity/EntityWidget.kt deleted file mode 100644 index 2e49072..0000000 --- a/src/main/kotlin/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 { - 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/gui/entity/ModifyEquipment.kt b/src/main/kotlin/gui/entity/ModifyEquipment.kt index 11dfb52..a558936 100644 --- a/src/main/kotlin/gui/entity/ModifyEquipment.kt +++ b/src/main/kotlin/gui/entity/ModifyEquipment.kt @@ -1,4 +1,3 @@ - package moe.nea.firmament.gui.entity import com.google.gson.JsonObject @@ -6,50 +5,49 @@ 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.repo.SBItemStack import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.mc.setEncodedSkullOwner import moe.nea.firmament.util.mc.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, - ) + 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 - } + 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 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 - } + 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/rei/FirmamentReiPlugin.kt b/src/main/kotlin/rei/FirmamentReiPlugin.kt deleted file mode 100644 index f234f3e..0000000 --- a/src/main/kotlin/rei/FirmamentReiPlugin.kt +++ /dev/null @@ -1,142 +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.MC -import moe.nea.firmament.util.ScreenUtil -import moe.nea.firmament.util.SkyblockId -import moe.nea.firmament.util.guessRecipeId -import moe.nea.firmament.util.skyblockId -import moe.nea.firmament.util.unformattedString - - -class FirmamentReiPlugin : REIClientPlugin { - - companion object { - fun EntryStack.asItemEntry(): EntryStack { - 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) return@TransferHandler TransferHandler.Result.createNotApplicable() - val neuItem = RepoManager.getNEUItem(SkyblockId(display.neuRecipe.output.itemId)) - ?: error("Could not find neu item ${display.neuRecipe.output.itemId} which is used in a recipe output") - val useSuperCraft = context.isStackedCrafting || RepoManager.Config.alwaysSuperCraft - if (neuItem.isVanilla && useSuperCraft) return@TransferHandler TransferHandler.Result.createFailed(Text.translatable( - "firmament.recipe.novanilla")) - var shouldReturn = true - if (context.isActuallyCrafting && !useSuperCraft) { - if (screen !is GenericContainerScreen || screen.title?.unformattedString != CraftingOverlay.CRAFTING_SCREEN_NAME) { - MC.sendCommand("craft") - shouldReturn = false - } - CraftingOverlay.setOverlay(screen as? GenericContainerScreen, display) - } - if (context.isActuallyCrafting && useSuperCraft) { - shouldReturn = false - MC.sendCommand("viewrecipe ${neuItem.guessRecipeId()}") - } - return@TransferHandler TransferHandler.Result.createSuccessful().blocksFurtherHandling(shouldReturn) - }) - } - - 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 isHandingScreen(screen: Class?): Boolean { - return screen == StorageOverlayScreen::class.java - } - - override fun 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/rei/NEUItemEntryRenderer.kt b/src/main/kotlin/rei/NEUItemEntryRenderer.kt deleted file mode 100644 index ba99b30..0000000 --- a/src/main/kotlin/rei/NEUItemEntryRenderer.kt +++ /dev/null @@ -1,186 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2018-2023 shedaniel - * SPDX-FileCopyrightText: 2023 Linnea Gräf - * SPDX-FileCopyrightText: 2024 Linnea Gräf - * - * 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, BatchedEntryRenderer { - override fun render( - entry: EntryStack, - 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, 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): BakedModel { - return minecraft.itemRenderer.getModel(entry.asItemEntry().value, minecraft.world, minecraft.player, 0) - } - - override fun getBatchIdentifier(entry: EntryStack?, bounds: Rectangle?, extraData: BakedModel): Int { - return 1738923 + if (extraData.isSideLit) 1 else 0 - } - - override fun startBatch( - entry: EntryStack, - 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, - 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, - 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, - 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) { - if (!entry.isEmpty) { - graphics.drawItemInSlot(MinecraftClient.getInstance().textRenderer, entry.value, 0, 0, null) - } - } - - override fun endBatch( - entry: EntryStack?, - extraData: BakedModel?, - graphics: DrawContext?, - delta: Float - ) { - } - -} diff --git a/src/main/kotlin/rei/NEUItemEntrySerializer.kt b/src/main/kotlin/rei/NEUItemEntrySerializer.kt deleted file mode 100644 index a35d75f..0000000 --- a/src/main/kotlin/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 { - 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, 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/rei/SBItemEntryDefinition.kt b/src/main/kotlin/rei/SBItemEntryDefinition.kt deleted file mode 100644 index 3df8fa3..0000000 --- a/src/main/kotlin/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.mc.appendLore -import moe.nea.firmament.util.mc.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 = 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 - ) { - 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) { - val petData = this.petData ?: return - val petInfo = RepoManager.neuRepo.constants.petNumbers[petData.petId]?.get(petData.rarity) ?: return - if (petData.isStub) { - val mapLow = mutableMapOf() - injectReplacementDataForPetLevel(petInfo, petInfo.lowLevel, mapLow) - val mapHigh = mutableMapOf() - 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() - 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 { - override fun equals(o1: SBItemStack, o2: SBItemStack, context: ComparisonContext): Boolean { - return o1.skyblockId == o2.skyblockId && o1.getStackSize() == o2.getStackSize() - } - - override fun cheatsAs(entry: EntryStack?, value: SBItemStack): ItemStack { - return value.asItemStack() - } - - override fun getValueType(): Class = SBItemStack::class.java - override fun getType(): EntryType = EntryType.deferred(FirmamentReiPlugin.SKYBLOCK_ITEM_TYPE_ID) - - override fun getRenderer(): EntryRenderer = NEUItemEntryRenderer - - override fun getSerializer(): EntrySerializer { - return NEUItemEntrySerializer - } - - override fun getTagsFor(entry: EntryStack?, value: SBItemStack?): Stream>? { - return Stream.empty() - } - - override fun asFormattedText(entry: EntryStack, value: SBItemStack): Text { - return VanillaEntryTypes.ITEM.definition.asFormattedText(entry.asItemEntry(), value.asImmutableItemStack()) - } - - override fun hash(entry: EntryStack, 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?, value: SBItemStack): SBItemStack { - return value.copy(stackSize = 1, petData = RepoManager.getPotentialStubPetData(value.skyblockId), - stars = 0, extraLore = listOf()) - } - - override fun normalize(entry: EntryStack?, value: SBItemStack): SBItemStack { - return wildcard(entry, value) - } - - override fun copy(entry: EntryStack?, value: SBItemStack): SBItemStack { - return value - } - - override fun isEmpty(entry: EntryStack?, value: SBItemStack): Boolean { - return value.getStackSize() == 0 - } - - override fun getIdentifier(entry: EntryStack?, value: SBItemStack): Identifier { - return value.skyblockId.identifier - } - - fun getEntry(sbItemStack: SBItemStack): EntryStack = - EntryStack.of(this, sbItemStack) - - fun getEntry(skyblockId: SkyblockId, count: Int = 1): EntryStack = - getEntry(SBItemStack(skyblockId, count)) - - fun getEntry(ingredient: NEUIngredient): EntryStack = - getEntry(SkyblockId(ingredient.itemId), count = ingredient.amount.toInt()) - - fun getEntry(stack: ItemStack): EntryStack = - 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/rei/SkyblockCraftingRecipeDynamicGenerator.kt b/src/main/kotlin/rei/SkyblockCraftingRecipeDynamicGenerator.kt deleted file mode 100644 index 5136902..0000000 --- a/src/main/kotlin/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(it) } - -val SkyblockForgeRecipeDynamicGenerator = - neuDisplayGenerator { SBForgeRecipe(it) } - -val SkyblockMobDropRecipeDynamicGenerator = - neuDisplayGenerator { SBMobDropRecipe(it) } - -val SkyblockKatRecipeDynamicGenerator = - neuDisplayGenerator { SBKatRecipe(it) } -val SkyblockEssenceRecipeDynamicGenerator = - neuDisplayGenerator { SBEssenceUpgradeRecipe(it) } - -inline fun neuDisplayGenerator(crossinline mapper: (T) -> D) = - object : DynamicDisplayGenerator { - override fun getRecipeFor(entry: EntryStack<*>): Optional> { - if (entry.type != SBItemEntryDefinition.type) return Optional.empty() - val item = entry.castValue() - val recipes = RepoManager.getRecipesFor(item.skyblockId) - val craftingRecipes = recipes.filterIsInstance() - return Optional.of(craftingRecipes.map(mapper)) - } - - override fun generate(builder: ViewSearchBuilder): Optional> { - if (SBCraftingRecipe.Category.catIdentifier !in builder.categories) return Optional.empty() - return Optional.of( - RepoManager.getAllRecipes().filterIsInstance().map { mapper(it) } - .toList() - ) - } - - override fun getUsageFor(entry: EntryStack<*>): Optional> { - if (entry.type != SBItemEntryDefinition.type) return Optional.empty() - val item = entry.castValue() - val recipes = RepoManager.getUsagesFor(item.skyblockId) - val craftingRecipes = recipes.filterIsInstance() - return Optional.of(craftingRecipes.map(mapper)) - - } - } diff --git a/src/main/kotlin/rei/SkyblockItemIdFocusedStackProvider.kt b/src/main/kotlin/rei/SkyblockItemIdFocusedStackProvider.kt deleted file mode 100644 index bb0a5a5..0000000 --- a/src/main/kotlin/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> { - 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/rei/math.kt b/src/main/kotlin/rei/math.kt deleted file mode 100644 index 1318beb..0000000 --- a/src/main/kotlin/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/rei/recipes/SBCraftingRecipe.kt b/src/main/kotlin/rei/recipes/SBCraftingRecipe.kt deleted file mode 100644 index d6bbf0c..0000000 --- a/src/main/kotlin/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 { - val catIdentifier = CategoryIdentifier.of(Firmament.MOD_ID, "crafing_recipe") - override fun getCategoryIdentifier(): CategoryIdentifier = 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 { - 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/rei/recipes/SBEssenceUpgradeRecipe.kt b/src/main/kotlin/rei/recipes/SBEssenceUpgradeRecipe.kt deleted file mode 100644 index 80bc2b7..0000000 --- a/src/main/kotlin/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 { - override fun getCategoryIdentifier(): CategoryIdentifier = - 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 { - val recipe = display.neuRecipe - val list = mutableListOf() - 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/rei/recipes/SBForgeRecipe.kt b/src/main/kotlin/rei/recipes/SBForgeRecipe.kt deleted file mode 100644 index 569f4a0..0000000 --- a/src/main/kotlin/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 { - override fun getCategoryIdentifier(): CategoryIdentifier = - 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 { - 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/rei/recipes/SBKatRecipe.kt b/src/main/kotlin/rei/recipes/SBKatRecipe.kt deleted file mode 100644 index f906a43..0000000 --- a/src/main/kotlin/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 { - override fun getCategoryIdentifier(): CategoryIdentifier = - 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 { - 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 { - 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/rei/recipes/SBMobDropRecipe.kt b/src/main/kotlin/rei/recipes/SBMobDropRecipe.kt deleted file mode 100644 index a02220f..0000000 --- a/src/main/kotlin/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 { - override fun getCategoryIdentifier(): CategoryIdentifier = - 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 { - 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() - 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/rei/recipes/SBRecipe.kt b/src/main/kotlin/rei/recipes/SBRecipe.kt deleted file mode 100644 index 7872d83..0000000 --- a/src/main/kotlin/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 { - 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 { - 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/repo/PetData.kt b/src/main/kotlin/repo/PetData.kt new file mode 100644 index 0000000..2ce3402 --- /dev/null +++ b/src/main/kotlin/repo/PetData.kt @@ -0,0 +1,24 @@ +package moe.nea.firmament.repo + +import io.github.moulberry.repo.data.Rarity +import moe.nea.firmament.util.HypixelPetInfo + +// 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) } +} diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt index ab0d9cf..b586548 100644 --- a/src/main/kotlin/repo/RepoManager.kt +++ b/src/main/kotlin/repo/RepoManager.kt @@ -14,7 +14,6 @@ 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 @@ -139,9 +138,9 @@ object RepoManager { return null } val intIndex = rarityIndex.toInt() - if (intIndex !in Rarity.values().indices) return null + if (intIndex !in Rarity.entries.indices) return null if (petId !in neuRepo.constants.petNumbers) return null - return PetData(Rarity.values()[intIndex], petId, 0.0, true) + return PetData(Rarity.entries[intIndex], petId, 0.0, true) } } diff --git a/src/main/kotlin/repo/SBItemStack.kt b/src/main/kotlin/repo/SBItemStack.kt new file mode 100644 index 0000000..281075d --- /dev/null +++ b/src/main/kotlin/repo/SBItemStack.kt @@ -0,0 +1,165 @@ +package moe.nea.firmament.repo + +import io.github.moulberry.repo.constants.PetNumbers +import io.github.moulberry.repo.data.NEUIngredient +import io.github.moulberry.repo.data.NEUItem +import net.minecraft.item.ItemStack +import net.minecraft.text.Text +import net.minecraft.util.Formatting +import moe.nea.firmament.repo.ItemCache.asItemStack +import moe.nea.firmament.util.FirmFormatters +import moe.nea.firmament.util.LegacyFormattingCode +import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.mc.appendLore +import moe.nea.firmament.util.mc.displayNameAccordingToNbt +import moe.nea.firmament.util.petData +import moe.nea.firmament.util.skyBlockId +import moe.nea.firmament.util.skyblockId +import moe.nea.firmament.util.withColor + +data class SBItemStack constructor( + val skyblockId: SkyblockId, + val neuItem: NEUItem?, + private var stackSize: Int, + private var petData: PetData?, + val extraLore: List = 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 + } + + companion object { + operator fun invoke(itemStack: ItemStack): SBItemStack { + val skyblockId = itemStack.skyBlockId ?: SkyblockId.NULL + return SBItemStack( + skyblockId, + RepoManager.getNEUItem(skyblockId), + itemStack.count, + petData = itemStack.petData?.let { PetData.fromHypixel(it) } + ) + } + + operator fun invoke(neuIngredient: NEUIngredient): SBItemStack? { + if (neuIngredient.skyblockId == SkyblockId.SENTINEL_EMPTY) return null // TODO: better fallback, maybe? + if (neuIngredient.skyblockId == SkyblockId.COINS) { + // TODO: specially handle coins to include the decimals + } + return SBItemStack(neuIngredient.skyblockId, neuIngredient.amount.toInt()) + } + } + + 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 + ) { + 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) { + val petData = this.petData ?: return + val petInfo = RepoManager.neuRepo.constants.petNumbers[petData.petId]?.get(petData.rarity) ?: return + if (petData.isStub) { + val mapLow = mutableMapOf() + injectReplacementDataForPetLevel(petInfo, petInfo.lowLevel, mapLow) + val mapHigh = mutableMapOf() + 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() + 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 asCopiedItemStack(): ItemStack { + return itemStack.copy() + } +} diff --git a/src/main/kotlin/util/HoveredItemStack.kt b/src/main/kotlin/util/HoveredItemStack.kt index 47a59d0..a2e4ad2 100644 --- a/src/main/kotlin/util/HoveredItemStack.kt +++ b/src/main/kotlin/util/HoveredItemStack.kt @@ -1,31 +1,27 @@ - - 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 com.google.auto.service.AutoService import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.item.ItemStack import moe.nea.firmament.mixins.accessor.AccessorHandledScreen +import moe.nea.firmament.util.compatloader.CompatLoader + +interface HoveredItemStackProvider { + fun provideHoveredItemStack(screen: HandledScreen<*>): ItemStack? + + companion object : CompatLoader(HoveredItemStackProvider::class) +} +@AutoService(HoveredItemStackProvider::class) +class VanillaScreenProvider : HoveredItemStackProvider { + override fun provideHoveredItemStack(screen: HandledScreen<*>): ItemStack? { + screen as AccessorHandledScreen + val vanillaSlot = screen.focusedSlot_Firmament?.stack + return vanillaSlot + } +} 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) - } - } + get() = + HoveredItemStackProvider.allValidInstances + .firstNotNullOfOrNull { it.provideHoveredItemStack(this) } diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt index 31227e2..059e746 100644 --- a/src/main/kotlin/util/SkyblockId.kt +++ b/src/main/kotlin/util/SkyblockId.kt @@ -2,6 +2,7 @@ package moe.nea.firmament.util +import io.github.moulberry.repo.data.NEUIngredient import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.Rarity import java.util.Optional @@ -61,7 +62,8 @@ value class SkyblockId(val neuItem: String) { } companion object { - val COINS: SkyblockId = SkyblockId("SKYBLOCK_COIN") + val COINS: SkyblockId = SkyblockId(NEUIngredient.NEU_SENTINEL_COINS) + val SENTINEL_EMPTY: SkyblockId = SkyblockId(NEUIngredient.NEU_SENTINEL_EMPTY) private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex() val NULL: SkyblockId = SkyblockId("null") val PET_NULL: SkyblockId = SkyblockId("null_pet") @@ -70,6 +72,7 @@ value class SkyblockId(val neuItem: String) { } val NEUItem.skyblockId get() = SkyblockId(skyblockItemId) +val NEUIngredient.skyblockId get() = SkyblockId(itemId) fun NEUItem.guessRecipeId(): String? { if (!skyblockItemId.contains(";")) return skyblockItemId diff --git a/src/main/kotlin/util/compatloader/CompatLoader.kt b/src/main/kotlin/util/compatloader/CompatLoader.kt index c5d45bc..6b60e87 100644 --- a/src/main/kotlin/util/compatloader/CompatLoader.kt +++ b/src/main/kotlin/util/compatloader/CompatLoader.kt @@ -2,10 +2,13 @@ package moe.nea.firmament.util.compatloader import java.util.ServiceLoader import net.fabricmc.loader.api.FabricLoader +import kotlin.reflect.KClass import kotlin.streams.asSequence import moe.nea.firmament.Firmament abstract class CompatLoader(val kClass: Class) { + constructor(kClass: KClass) : this(kClass.java) + val loader: ServiceLoader = ServiceLoader.load(kClass) val allValidInstances by lazy { loader.reload() diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 08072ef..b40514e 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -31,7 +31,7 @@ "moe.nea.firmament.Firmament::onClientInitialize" ], "rei_client": [ - "moe.nea.firmament.rei.FirmamentReiPlugin" + "moe.nea.firmament.compat.rei.FirmamentReiPlugin" ], "modmenu": [ "moe.nea.firmament.compat.modmenu.FirmamentModMenuPlugin" -- cgit