diff options
| author | Linnea Gräf <nea@nea.moe> | 2024-10-28 12:07:55 +0100 |
|---|---|---|
| committer | Linnea Gräf <nea@nea.moe> | 2024-10-28 12:07:55 +0100 |
| commit | c38dcee2c5f483ef5990ae9204355e1bc3c2bf74 (patch) | |
| tree | 3b70359076001e14514c496e3c44980fdbd92d01 /src/compat/rei/java | |
| parent | 8ab44088546bf3360564e1a09f0831fea7659d2e (diff) | |
| download | Firmament-c38dcee2c5f483ef5990ae9204355e1bc3c2bf74.tar.gz Firmament-c38dcee2c5f483ef5990ae9204355e1bc3c2bf74.tar.bz2 Firmament-c38dcee2c5f483ef5990ae9204355e1bc3c2bf74.zip | |
Make REI optional
Diffstat (limited to 'src/compat/rei/java')
15 files changed, 1175 insertions, 0 deletions
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<Element> { + return emptyList() + } + + var hasErrored = false + + override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { + try { + if (!hasErrored) + EntityRenderer.renderEntity(entity, context, point.x, point.y, mouseX.toFloat(), mouseY.toFloat()) + } catch (ex: Exception) { + EntityRenderer.logger.error("Failed to render constructed entity: $entity", ex) + hasErrored = true + } + if (hasErrored) { + context.fill(point.x, point.y, point.x + 50, point.y + 80, 0xFFAA2222.toInt()) + } + } + + override fun getBounds(): Rectangle { + return Rectangle(point, Dimension(50, 80)) + } +} diff --git a/src/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<SBItemStack>.asItemEntry(): EntryStack<ItemStack> { + return EntryStack.of(VanillaEntryTypes.ITEM, value.asImmutableItemStack()) + } + + val SKYBLOCK_ITEM_TYPE_ID = Identifier.of("firmament", "skyblockitems") + } + + override fun registerTransferHandlers(registry: TransferHandlerRegistry) { + registry.register(TransferHandler { context -> + val screen = context.containerScreen + val display = context.display + if (display !is SBCraftingRecipe) 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 <R : Screen?> isHandingScreen(screen: Class<R>?): Boolean { + return screen == StorageOverlayScreen::class.java + } + + override fun <R : Screen?> shouldScreenBeOverlaid(screen: R): ActionResult { + return ActionResult.SUCCESS + } + }) + registry.registerFocusedStack(SkyblockItemIdFocusedStackProvider) + } + + override fun registerEntries(registry: EntryRegistry) { + registry.removeEntryIf { true } + RepoManager.neuRepo.items?.items?.values?.forEach { neuItem -> + registry.addEntry(SBItemEntryDefinition.getEntry(neuItem.skyblockId)) + } + } +} diff --git a/src/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 <daniel@shedaniel.me> + * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + * SPDX-License-Identifier: MIT + */ + +package moe.nea.firmament.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<SBItemStack>, BatchedEntryRenderer<SBItemStack, BakedModel> { + override fun render( + entry: EntryStack<SBItemStack>, + context: DrawContext, + bounds: Rectangle, + mouseX: Int, + mouseY: Int, + delta: Float + ) { + entry.asItemEntry().render(context, bounds, mouseX, mouseY, delta) + } + + val minecraft = MinecraftClient.getInstance() + + override fun getTooltip(entry: EntryStack<SBItemStack>, tooltipContext: TooltipContext): Tooltip? { + val stack = entry.value.asImmutableItemStack() + val lore = stack.getTooltip( + Item.TooltipContext.DEFAULT, + null, + TooltipType.BASIC + ) + return Tooltip.create(lore) + } + + override fun getExtraData(entry: EntryStack<SBItemStack>): BakedModel { + return minecraft.itemRenderer.getModel(entry.asItemEntry().value, minecraft.world, minecraft.player, 0) + } + + override fun getBatchIdentifier(entry: EntryStack<SBItemStack>?, bounds: Rectangle?, extraData: BakedModel): Int { + return 1738923 + if (extraData.isSideLit) 1 else 0 + } + + override fun startBatch( + entry: EntryStack<SBItemStack>, + model: BakedModel, + graphics: DrawContext, + delta: Float + ) { + val modelViewStack = RenderSystem.getModelViewStack() + modelViewStack.pushMatrix() + modelViewStack.scale(20.0f, 20.0f, 1.0f) + RenderSystem.applyModelViewMatrix() + setupGL(model) + } + + fun setupGL(model: BakedModel) { + minecraft.textureManager.getTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE) + .setFilter(false, false) + RenderSystem.setShaderTexture(0, SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE) + RenderSystem.enableBlend() + RenderSystem.blendFunc(SrcFactor.SRC_ALPHA, DstFactor.ONE_MINUS_SRC_ALPHA) + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) + val sideLit = model.isSideLit + if (!sideLit) { + DiffuseLighting.disableGuiDepthLighting() + } + } + + override fun renderBase( + entry: EntryStack<SBItemStack>, + model: BakedModel, + graphics: DrawContext, + immediate: VertexConsumerProvider.Immediate, + bounds: Rectangle, + mouseX: Int, + mouseY: Int, + delta: Float + ) { + if (entry.isEmpty) return + val value = entry.asItemEntry().value + graphics.matrices.push() + graphics.matrices.translate(bounds.centerX.toFloat() / 20.0f, bounds.centerY.toFloat() / 20.0f, 0.0f) + graphics.matrices.scale( + bounds.getWidth().toFloat() / 20.0f, + -(bounds.getWidth() + bounds.getHeight()).toFloat() / 2.0f / 20.0f, + 1.0f + ) + minecraft + .itemRenderer + .renderItem( + value, + ModelTransformationMode.GUI, + false, + graphics.matrices, + immediate, + LightmapTextureManager.MAX_LIGHT_COORDINATE, + OverlayTexture.DEFAULT_UV, + model + ) + graphics.matrices.pop() + + } + + override fun afterBase( + entry: EntryStack<SBItemStack>, + model: BakedModel, + graphics: DrawContext, + delta: Float + ) { + RenderSystem.getModelViewStack().popMatrix() + RenderSystem.applyModelViewMatrix() + this.endGL(model) + } + + fun endGL(model: BakedModel) { + RenderSystem.enableDepthTest() + val sideLit = model.isSideLit + if (!sideLit) { + DiffuseLighting.enableGuiDepthLighting() + } + } + + override fun renderOverlay( + entry: EntryStack<SBItemStack>, + extraData: BakedModel, + graphics: DrawContext, + immediate: VertexConsumerProvider.Immediate, + bounds: Rectangle, + mouseX: Int, + mouseY: Int, + delta: Float + ) { + val modelViewStack = RenderSystem.getModelViewStack() + modelViewStack.pushMatrix() + modelViewStack.mul(graphics.matrices.peek().positionMatrix) + modelViewStack.translate(bounds.x.toFloat(), bounds.y.toFloat(), 0.0f) + modelViewStack.scale( + bounds.width.toFloat() / 16.0f, + -(bounds.getWidth() + bounds.getHeight()).toFloat() / 2.0f / 16.0f, + 1.0f + ) + RenderSystem.applyModelViewMatrix() + renderOverlay(DrawContext(minecraft, graphics.vertexConsumers), entry.asItemEntry()) + modelViewStack.popMatrix() + RenderSystem.applyModelViewMatrix() + } + + fun renderOverlay(graphics: DrawContext, entry: EntryStack<ItemStack>) { + if (!entry.isEmpty) { + graphics.drawItemInSlot(MinecraftClient.getInstance().textRenderer, entry.value, 0, 0, null) + } + } + + override fun endBatch( + entry: EntryStack<SBItemStack>?, + extraData: BakedModel?, + graphics: DrawContext?, + delta: Float + ) { + } + +} diff --git a/src/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<SBItemStack> { + const val SKYBLOCK_ID_ENTRY = "SKYBLOCK_ID" + const val SKYBLOCK_ITEM_COUNT = "SKYBLOCK_ITEM_COUNT" + + override fun supportSaving(): Boolean = true + override fun supportReading(): Boolean = true + + override fun read(tag: NbtCompound): SBItemStack { + val id = SkyblockId(tag.getString(SKYBLOCK_ID_ENTRY)) + val count = if (tag.contains(SKYBLOCK_ITEM_COUNT)) tag.getInt(SKYBLOCK_ITEM_COUNT) else 1 + return SBItemStack(id, count) + } + + override fun save(entry: EntryStack<SBItemStack>, value: SBItemStack): NbtCompound { + return NbtCompound().apply { + putString(SKYBLOCK_ID_ENTRY, value.skyblockId.neuItem) + putInt(SKYBLOCK_ITEM_COUNT, value.getStackSize()) + } + } +} diff --git a/src/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<SBItemStack> { + override fun equals(o1: SBItemStack, o2: SBItemStack, context: ComparisonContext): Boolean { + return o1.skyblockId == o2.skyblockId && o1.getStackSize() == o2.getStackSize() + } + + override fun cheatsAs(entry: EntryStack<SBItemStack>?, value: SBItemStack): ItemStack { + return value.asCopiedItemStack() + } + + override fun getValueType(): Class<SBItemStack> = SBItemStack::class.java + override fun getType(): EntryType<SBItemStack> = EntryType.deferred(FirmamentReiPlugin.SKYBLOCK_ITEM_TYPE_ID) + + override fun getRenderer(): EntryRenderer<SBItemStack> = NEUItemEntryRenderer + + override fun getSerializer(): EntrySerializer<SBItemStack> { + return NEUItemEntrySerializer + } + + override fun getTagsFor(entry: EntryStack<SBItemStack>?, value: SBItemStack?): Stream<out TagKey<*>>? { + return Stream.empty() + } + + override fun asFormattedText(entry: EntryStack<SBItemStack>, value: SBItemStack): Text { + return VanillaEntryTypes.ITEM.definition.asFormattedText(entry.asItemEntry(), value.asImmutableItemStack()) + } + + override fun hash(entry: EntryStack<SBItemStack>, value: SBItemStack, context: ComparisonContext): Long { + // Repo items are immutable, and get replaced entirely when loaded from disk + return value.skyblockId.hashCode() * 31L + } + + override fun wildcard(entry: EntryStack<SBItemStack>?, value: SBItemStack): SBItemStack { + return value.copy(stackSize = 1, petData = RepoManager.getPotentialStubPetData(value.skyblockId), + stars = 0, extraLore = listOf()) + } + + override fun normalize(entry: EntryStack<SBItemStack>?, value: SBItemStack): SBItemStack { + return wildcard(entry, value) + } + + override fun copy(entry: EntryStack<SBItemStack>?, value: SBItemStack): SBItemStack { + return value + } + + override fun isEmpty(entry: EntryStack<SBItemStack>?, value: SBItemStack): Boolean { + return value.getStackSize() == 0 + } + + override fun getIdentifier(entry: EntryStack<SBItemStack>?, value: SBItemStack): Identifier { + return value.skyblockId.identifier + } + + fun getEntry(sbItemStack: SBItemStack): EntryStack<SBItemStack> = + EntryStack.of(this, sbItemStack) + + fun getEntry(skyblockId: SkyblockId, count: Int = 1): EntryStack<SBItemStack> = + getEntry(SBItemStack(skyblockId, count)) + + fun getEntry(ingredient: NEUIngredient): EntryStack<SBItemStack> = + getEntry(SkyblockId(ingredient.itemId), count = ingredient.amount.toInt()) + + fun getEntry(stack: ItemStack): EntryStack<SBItemStack> = + getEntry( + SBItemStack( + stack.skyBlockId ?: SkyblockId.NULL, + RepoManager.getNEUItem(stack.skyBlockId ?: SkyblockId.NULL), + stack.count, + petData = stack.petData?.let { PetData.fromHypixel(it) } + ) + ) +} diff --git a/src/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, NEUCraftingRecipe> { SBCraftingRecipe(it) } + +val SkyblockForgeRecipeDynamicGenerator = + neuDisplayGenerator<SBForgeRecipe, NEUForgeRecipe> { SBForgeRecipe(it) } + +val SkyblockMobDropRecipeDynamicGenerator = + neuDisplayGenerator<SBMobDropRecipe, NEUMobDropRecipe> { SBMobDropRecipe(it) } + +val SkyblockKatRecipeDynamicGenerator = + neuDisplayGenerator<SBKatRecipe, NEUKatUpgradeRecipe> { SBKatRecipe(it) } +val SkyblockEssenceRecipeDynamicGenerator = + neuDisplayGenerator<SBEssenceUpgradeRecipe, EssenceRecipeProvider.EssenceUpgradeRecipe> { SBEssenceUpgradeRecipe(it) } + +inline fun <D : Display, reified T : NEURecipe> neuDisplayGenerator(crossinline mapper: (T) -> D) = + object : DynamicDisplayGenerator<D> { + override fun getRecipeFor(entry: EntryStack<*>): Optional<List<D>> { + if (entry.type != SBItemEntryDefinition.type) return Optional.empty() + val item = entry.castValue<SBItemStack>() + val recipes = RepoManager.getRecipesFor(item.skyblockId) + val craftingRecipes = recipes.filterIsInstance<T>() + return Optional.of(craftingRecipes.map(mapper)) + } + + override fun generate(builder: ViewSearchBuilder): Optional<List<D>> { + if (SBCraftingRecipe.Category.catIdentifier !in builder.categories) return Optional.empty() + return Optional.of( + RepoManager.getAllRecipes().filterIsInstance<T>().map { mapper(it) } + .toList() + ) + } + + override fun getUsageFor(entry: EntryStack<*>): Optional<List<D>> { + if (entry.type != SBItemEntryDefinition.type) return Optional.empty() + val item = entry.castValue<SBItemStack>() + val recipes = RepoManager.getUsagesFor(item.skyblockId) + val craftingRecipes = recipes.filterIsInstance<T>() + return Optional.of(craftingRecipes.map(mapper)) + + } + } diff --git a/src/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<EntryStack<*>> { + if (screen !is HandledScreen<*>) return CompoundEventResult.pass() + screen as AccessorHandledScreen + val focusedSlot = screen.focusedSlot_Firmament ?: return CompoundEventResult.pass() + val item = focusedSlot.stack ?: return CompoundEventResult.pass() + val skyblockId = item.skyBlockId ?: return CompoundEventResult.pass() + return CompoundEventResult.interruptTrue(SBItemEntryDefinition.getEntry(skyblockId)) + } + + override fun getPriority(): Double = 1_000_000.0 +} diff --git a/src/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<SBCraftingRecipe> { + val catIdentifier = CategoryIdentifier.of<SBCraftingRecipe>(Firmament.MOD_ID, "crafing_recipe") + override fun getCategoryIdentifier(): CategoryIdentifier<out SBCraftingRecipe> = catIdentifier + + override fun getTitle(): Text = Text.literal("SkyBlock Crafting") + + override fun getIcon(): Renderer = EntryStacks.of(Blocks.CRAFTING_TABLE) + override fun setupDisplay(display: SBCraftingRecipe, bounds: Rectangle): List<Widget> { + val point = Point(bounds.centerX - 58, bounds.centerY - 27) + return buildList { + add(Widgets.createRecipeBase(bounds)) + add(Widgets.createArrow(Point(point.x + 60, point.y + 18))) + add(Widgets.createResultSlotBackground(Point(point.x + 95, point.y + 19))) + for (i in 0 until 3) { + for (j in 0 until 3) { + val slot = Widgets.createSlot(Point(point.x + 1 + i * 18, point.y + 1 + j * 18)).markInput() + add(slot) + val item = display.neuRecipe.inputs[i + j * 3] + if (item == NEUIngredient.SENTINEL_EMPTY) continue + slot.entry(SBItemEntryDefinition.getEntry(item)) // TODO: make use of stackable item entries + } + } + add( + Widgets.createSlot(Point(point.x + 95, point.y + 19)) + .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.output)) + .disableBackground().markOutput() + ) + } + } + + } + +} diff --git a/src/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 |
