aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt40
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt10
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt11
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/HoveredItemStackProvider.kt1
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt271
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntrySerializer.kt31
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/math.kt6
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBCraftingRecipe.kt70
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBEssenceUpgradeRecipe.kt79
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBForgeRecipe.kt90
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBKatRecipe.kt370
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt167
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBRecipe.kt47
-rw-r--r--src/compat/sodium/java/SodiumChunkReloader.kt2
-rw-r--r--src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java8
-rw-r--r--src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java4
-rw-r--r--src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java6
-rw-r--r--src/main/java/moe/nea/firmament/mixins/CustomModelBakerPatch.java49
-rw-r--r--src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java18
-rw-r--r--src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java9
-rw-r--r--src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java1
-rw-r--r--src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java31
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MainWindowFirstLoadPatch.java31
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java22
-rw-r--r--src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java9
-rw-r--r--src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java8
-rw-r--r--src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java11
-rw-r--r--src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java46
-rw-r--r--src/main/java/moe/nea/firmament/mixins/accessor/AccessorGameRenderer.java14
-rw-r--r--src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java24
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java40
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java18
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/HeadModelReplacerPatch.java57
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java22
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java69
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java28
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/PatchHeadFeatureRenderer.java45
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/PatchLegacyArmorLayerSupport.java22
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java46
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/ProvideBakerToJsonUnbakedModelPatch.java27
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/ReferenceCustomModelsPatch.java37
-rw-r--r--src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java56
-rw-r--r--src/main/kotlin/events/BakeExtraModelsEvent.kt25
-rw-r--r--src/main/kotlin/events/CustomItemModelEvent.kt46
-rw-r--r--src/main/kotlin/events/DebugInstantiateEvent.kt9
-rw-r--r--src/main/kotlin/events/FinalizeResourceManagerEvent.kt41
-rw-r--r--src/main/kotlin/events/IsSlotProtectedEvent.kt2
-rw-r--r--src/main/kotlin/events/RegisterCustomShadersEvent.kt24
-rw-r--r--src/main/kotlin/events/SlotRenderEvents.kt15
-rw-r--r--src/main/kotlin/events/WorldReadyEvent.kt9
-rw-r--r--src/main/kotlin/events/WorldRenderLastEvent.kt3
-rw-r--r--src/main/kotlin/features/chat/ChatLinks.kt3
-rw-r--r--src/main/kotlin/features/debug/DeveloperFeatures.kt4
-rw-r--r--src/main/kotlin/features/debug/PowerUserTools.kt17
-rw-r--r--src/main/kotlin/features/diana/AncestralSpadeSolver.kt5
-rw-r--r--src/main/kotlin/features/diana/NearbyBurrowsSolver.kt238
-rw-r--r--src/main/kotlin/features/inventory/CraftingOverlay.kt2
-rw-r--r--src/main/kotlin/features/inventory/ItemRarityCosmetics.kt16
-rw-r--r--src/main/kotlin/features/inventory/PetFeatures.kt5
-rw-r--r--src/main/kotlin/features/inventory/SlotLocking.kt36
-rw-r--r--src/main/kotlin/features/inventory/buttons/InventoryButton.kt5
-rw-r--r--src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt1
-rw-r--r--src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt1
-rw-r--r--src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt7
-rw-r--r--src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt2
-rw-r--r--src/main/kotlin/features/mining/CommissionFeatures.kt8
-rw-r--r--src/main/kotlin/features/mining/HotmPresets.kt7
-rw-r--r--src/main/kotlin/features/texturepack/BakedModelExtra.kt23
-rw-r--r--src/main/kotlin/features/texturepack/CustomBlockTextures.kt4
-rw-r--r--src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt213
-rw-r--r--src/main/kotlin/features/texturepack/CustomGlobalTextures.kt2
-rw-r--r--src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt2
-rw-r--r--src/main/kotlin/features/texturepack/TintOverrides.kt18
-rw-r--r--src/main/kotlin/features/world/FairySouls.kt4
-rw-r--r--src/main/kotlin/features/world/Waypoints.kt493
-rw-r--r--src/main/kotlin/gui/BarComponent.kt182
-rw-r--r--src/main/kotlin/gui/entity/EntityRenderer.kt331
-rw-r--r--src/main/kotlin/gui/entity/FakeWorld.kt702
-rw-r--r--src/main/kotlin/gui/entity/GuiPlayer.kt63
-rw-r--r--src/main/kotlin/gui/entity/ModifyHorse.kt11
-rw-r--r--src/main/kotlin/repo/RepoDownloadManager.kt2
-rw-r--r--src/main/kotlin/repo/RepoManager.kt8
-rw-r--r--src/main/kotlin/repo/SBItemStack.kt22
-rw-r--r--src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt19
-rw-r--r--src/main/kotlin/repo/recipes/RecipeLayouter.kt33
-rw-r--r--src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt50
-rw-r--r--src/main/kotlin/util/ErrorUtil.kt25
-rw-r--r--src/main/kotlin/util/MC.kt28
-rw-r--r--src/main/kotlin/util/SBData.kt2
-rw-r--r--src/main/kotlin/util/SkyblockId.kt7
-rw-r--r--src/main/kotlin/util/data/IDataHolder.kt112
-rw-r--r--src/main/kotlin/util/render/DrawContextExt.kt71
-rw-r--r--src/main/kotlin/util/render/FacingThePlayerContext.kt7
-rw-r--r--src/main/kotlin/util/render/FirmamentShaders.kt31
-rw-r--r--src/main/kotlin/util/render/RenderCircleProgress.kt140
-rw-r--r--src/main/kotlin/util/render/RenderInWorldContext.kt550
-rw-r--r--src/main/resources/assets/firmament/shaders/core/rendertype_lines.fsh (renamed from src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh)0
-rw-r--r--src/main/resources/assets/firmament/shaders/core/rendertype_lines.json (renamed from src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json)6
-rw-r--r--src/main/resources/assets/firmament/shaders/core/rendertype_lines.vsh (renamed from src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh)0
-rw-r--r--src/main/resources/fabric.mod.json3
-rw-r--r--src/main/resources/firmament.accesswidener4
-rw-r--r--src/main/resources/firmament.mixins.json13
102 files changed, 2932 insertions, 2733 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
index 9b7b190..b0efc98 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/EntityWidget.kt
@@ -4,32 +4,32 @@ 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
+import moe.nea.firmament.gui.entity.EntityRenderer
class EntityWidget(val entity: LivingEntity, val point: Point) : WidgetWithBounds() {
- override fun children(): List<Element> {
- return emptyList()
- }
+ override fun children(): List<Element> {
+ return emptyList()
+ }
- var hasErrored = false
+ 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 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))
- }
+ override fun getBounds(): Rectangle {
+ return Rectangle(point, Dimension(50, 80))
+ }
}
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt
new file mode 100644
index 0000000..98ac276
--- /dev/null
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt
@@ -0,0 +1,10 @@
+package moe.nea.firmament.compat.rei
+
+import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry
+import me.shedaniel.rei.api.common.plugins.REICommonPlugin
+
+class FirmamentReiCommonPlugin : REICommonPlugin {
+ override fun registerEntryTypes(registry: EntryTypeRegistry) {
+ registry.register(FirmamentReiPlugin.SKYBLOCK_ITEM_TYPE_ID, SBItemEntryDefinition)
+ }
+}
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
index d95d2d1..f576eda 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt
@@ -11,7 +11,6 @@ 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
@@ -20,18 +19,17 @@ 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.events.HandledScreenPushREIEvent
+import moe.nea.firmament.features.inventory.CraftingOverlay
+import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
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
@@ -74,9 +72,6 @@ class FirmamentReiPlugin : REIClientPlugin {
})
}
- override fun registerEntryTypes(registry: EntryTypeRegistry) {
- registry.register(SKYBLOCK_ITEM_TYPE_ID, SBItemEntryDefinition)
- }
override fun registerCategories(registry: CategoryRegistry) {
registry.add(SBCraftingRecipe.Category)
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
index 3d21b66..b917c3e 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/HoveredItemStackProvider.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/HoveredItemStackProvider.kt
@@ -21,6 +21,7 @@ class ScreenRegistryHoveredItemStackProvider : HoveredItemStackProvider {
return entryStack.value as? ItemStack ?: entryStack.cheatsAs().value
}
}
+
@AutoService(HoveredItemStackProvider::class)
@CompatLoader.RequireMod("roughlyenoughitems")
class OverlayHoveredItemStackProvider : HoveredItemStackProvider {
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
index a02742b..de173ff 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt
@@ -25,163 +25,128 @@ 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 net.minecraft.item.ModelTransformationMode
import moe.nea.firmament.compat.rei.FirmamentReiPlugin.Companion.asItemEntry
import moe.nea.firmament.repo.SBItemStack
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.mc.displayNameAccordingToNbt
+import moe.nea.firmament.util.mc.loreAccordingToNbt
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
- ) {
- }
+ 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 = mutableListOf(stack.displayNameAccordingToNbt)
+ lore.addAll(stack.loreAccordingToNbt)
+
+ // TODO: tags aren't sent as early now so some tooltip components that use tags will crash the game
+// stack.getTooltip(
+// Item.TooltipContext.create(
+// tooltipContext.vanillaContext().registryLookup
+// ?: MC.defaultRegistries
+// ),
+// MC.player,
+// TooltipType.BASIC
+// )
+ return Tooltip.create(lore)
+ }
+
+ override fun getExtraData(entry: EntryStack<SBItemStack>): BakedModel {
+ return MC.itemRenderer.getModel(entry.asItemEntry().value,
+ MC.world,
+ MC.player, 0)
+
+ }
+
+ override fun getBatchIdentifier(entry: EntryStack<SBItemStack>, bounds: Rectangle?, extraData: BakedModel): Int {
+ return 1738923 + if (extraData.isSideLit) 1 else 0
+ }
+
+
+ override fun startBatch(entryStack: EntryStack<SBItemStack>, e: BakedModel, drawContext: DrawContext, v: Float) {
+ MC.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)
+ if (!e.isSideLit) {
+ DiffuseLighting.disableGuiDepthLighting()
+ }
+ }
+
+ override fun renderBase(
+ entryStack: EntryStack<SBItemStack>,
+ model: BakedModel,
+ drawContext: DrawContext,
+ immediate: VertexConsumerProvider.Immediate,
+ bounds: Rectangle,
+ i: Int,
+ i1: Int,
+ v: Float
+ ) {
+ if (entryStack.isEmpty) return
+ drawContext.matrices.push()
+ drawContext.matrices.translate(bounds.centerX.toDouble(), bounds.centerY.toDouble(), 0.0)
+ // TODO: check the scaling here again
+ drawContext.matrices.scale(
+ bounds.width.toFloat(),
+ (bounds.height + bounds.height) / -2F,
+ (bounds.width + bounds.height) / 2f)
+ MC.itemRenderer.renderItem(
+ entryStack.value.asImmutableItemStack(),
+ ModelTransformationMode.GUI,
+ false, drawContext.matrices,
+ immediate, LightmapTextureManager.MAX_LIGHT_COORDINATE,
+ OverlayTexture.DEFAULT_UV,
+ model
+ )
+ drawContext.matrices.pop()
+ }
+
+ override fun afterBase(entryStack: EntryStack<SBItemStack>?, e: BakedModel, drawContext: DrawContext?, v: Float) {
+ RenderSystem.enableDepthTest()
+ if (!e.isSideLit)
+ DiffuseLighting.enableGuiDepthLighting()
+ }
+
+ override fun renderOverlay(
+ entryStack: EntryStack<SBItemStack>,
+ e: BakedModel,
+ drawContext: DrawContext,
+ immediate: VertexConsumerProvider.Immediate,
+ bounds: Rectangle,
+ i: Int,
+ i1: Int,
+ v: Float
+ ) {
+ if (entryStack.isEmpty) return
+ val modelViewStack = RenderSystem.getModelViewStack()
+ modelViewStack.pushMatrix()
+ modelViewStack.mul(drawContext.matrices.peek().positionMatrix)
+ modelViewStack.translate(bounds.x.toFloat(), bounds.y.toFloat(), 0F)
+ modelViewStack.scale(bounds.width / 16.0f,
+ (bounds.width + bounds.height) / 2.0f / 16.0f,
+ 1.0f) // TODO: weird scale again
+ drawContext.drawStackOverlay(MC.font, entryStack.value.asImmutableItemStack(), 0, 0, null)
+ modelViewStack.popMatrix()
+ }
+
+ override fun endBatch(entryStack: EntryStack<SBItemStack>?, e: BakedModel?, drawContext: DrawContext?, v: 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
index 6a03a48..724d193 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntrySerializer.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntrySerializer.kt
@@ -1,30 +1,17 @@
-
-
package moe.nea.firmament.compat.rei
+import com.mojang.serialization.Codec
import me.shedaniel.rei.api.common.entry.EntrySerializer
-import me.shedaniel.rei.api.common.entry.EntryStack
-import net.minecraft.nbt.NbtCompound
+import net.minecraft.network.RegistryByteBuf
+import net.minecraft.network.codec.PacketCodec
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 codec(): Codec<SBItemStack> {
+ return SBItemStack.CODEC
+ }
- 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())
- }
- }
+ override fun streamCodec(): PacketCodec<RegistryByteBuf, SBItemStack> {
+ return SBItemStack.PACKET_CODEC.cast()
+ }
}
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
index 7db36f2..f4808c7 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/math.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/math.kt
@@ -1,10 +1,8 @@
-
-
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,
+ 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
index ed18c6e..fd04abc 100644
--- 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
@@ -1,5 +1,3 @@
-
-
package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUCraftingRecipe
@@ -11,6 +9,8 @@ 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.display.Display
+import me.shedaniel.rei.api.common.display.DisplaySerializer
import me.shedaniel.rei.api.common.util.EntryStacks
import net.minecraft.block.Blocks
import net.minecraft.text.Text
@@ -18,38 +18,38 @@ 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()
- )
- }
- }
-
- }
+ 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
index f81d529..ec71ec8 100644
--- 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
@@ -1,4 +1,3 @@
-
package moe.nea.firmament.compat.rei.recipes
import me.shedaniel.math.Point
@@ -16,47 +15,47 @@ import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.SkyblockId
class SBEssenceUpgradeRecipe(override val neuRecipe: EssenceRecipeProvider.EssenceUpgradeRecipe) : SBRecipe() {
- object Category : DisplayCategory<SBEssenceUpgradeRecipe> {
- override fun getCategoryIdentifier(): CategoryIdentifier<SBEssenceUpgradeRecipe> =
- CategoryIdentifier.of(Firmament.MOD_ID, "essence_upgrade")
+ object Category : DisplayCategory<SBEssenceUpgradeRecipe> {
+ override fun getCategoryIdentifier(): CategoryIdentifier<SBEssenceUpgradeRecipe> =
+ CategoryIdentifier.of(Firmament.MOD_ID, "essence_upgrade")
- override fun getTitle(): Text {
- return Text.literal("Essence Upgrades")
- }
+ override fun getTitle(): Text {
+ return Text.literal("Essence Upgrades")
+ }
- override fun getIcon(): Renderer {
- return SBItemEntryDefinition.getEntry(SkyblockId("ESSENCE_WITHER"))
- }
+ override fun getIcon(): Renderer {
+ return SBItemEntryDefinition.getEntry(SkyblockId("ESSENCE_WITHER"))
+ }
- override fun setupDisplay(display: SBEssenceUpgradeRecipe, bounds: Rectangle): List<Widget> {
- val recipe = display.neuRecipe
- val list = mutableListOf<Widget>()
- list.add(Widgets.createRecipeBase(bounds))
- list.add(Widgets.createSlot(Point(bounds.minX + 12, bounds.centerY - 8 - 18 / 2))
- .markInput()
- .entry(SBItemEntryDefinition.getEntry(SBItemStack(recipe.itemId).copy(stars = recipe.starCountAfter - 1))))
- list.add(Widgets.createSlot(Point(bounds.minX + 12, bounds.centerY - 8 + 18 / 2))
- .markInput()
- .entry(SBItemEntryDefinition.getEntry(recipe.essenceIngredient)))
- list.add(Widgets.createSlot(Point(bounds.maxX - 12 - 16, bounds.centerY - 8))
- .markOutput()
- .entry(SBItemEntryDefinition.getEntry(SBItemStack(recipe.itemId).copy(stars = recipe.starCountAfter))))
- val extraItems = recipe.extraItems
- list.add(Widgets.createArrow(Point(bounds.centerX - 24 / 2,
- if (extraItems.isEmpty()) bounds.centerY - 17 / 2
- else bounds.centerY + 18 / 2)))
- for ((index, item) in extraItems.withIndex()) {
- list.add(Widgets.createSlot(
- Point(bounds.centerX - extraItems.size * 16 / 2 - 2 / 2 + index * 18,
- bounds.centerY - 18 / 2))
- .markInput()
- .entry(SBItemEntryDefinition.getEntry(item)))
- }
- return list
- }
- }
+ override fun setupDisplay(display: SBEssenceUpgradeRecipe, bounds: Rectangle): List<Widget> {
+ val recipe = display.neuRecipe
+ val list = mutableListOf<Widget>()
+ list.add(Widgets.createRecipeBase(bounds))
+ list.add(Widgets.createSlot(Point(bounds.minX + 12, bounds.centerY - 8 - 18 / 2))
+ .markInput()
+ .entry(SBItemEntryDefinition.getEntry(SBItemStack(recipe.itemId).copy(stars = recipe.starCountAfter - 1))))
+ list.add(Widgets.createSlot(Point(bounds.minX + 12, bounds.centerY - 8 + 18 / 2))
+ .markInput()
+ .entry(SBItemEntryDefinition.getEntry(recipe.essenceIngredient)))
+ list.add(Widgets.createSlot(Point(bounds.maxX - 12 - 16, bounds.centerY - 8))
+ .markOutput()
+ .entry(SBItemEntryDefinition.getEntry(SBItemStack(recipe.itemId).copy(stars = recipe.starCountAfter))))
+ val extraItems = recipe.extraItems
+ list.add(Widgets.createArrow(Point(bounds.centerX - 24 / 2,
+ if (extraItems.isEmpty()) bounds.centerY - 17 / 2
+ else bounds.centerY + 18 / 2)))
+ for ((index, item) in extraItems.withIndex()) {
+ list.add(Widgets.createSlot(
+ Point(bounds.centerX - extraItems.size * 16 / 2 - 2 / 2 + index * 18,
+ bounds.centerY - 18 / 2))
+ .markInput()
+ .entry(SBItemEntryDefinition.getEntry(item)))
+ }
+ return list
+ }
+ }
- override fun getCategoryIdentifier(): CategoryIdentifier<*> {
- return Category.categoryIdentifier
- }
+ 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
index bb51021..96af3fd 100644
--- 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
@@ -1,5 +1,3 @@
-
-
package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUForgeRecipe
@@ -21,51 +19,53 @@ 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
+ override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier
- object Category : DisplayCategory<SBForgeRecipe> {
- override fun getCategoryIdentifier(): CategoryIdentifier<SBForgeRecipe> =
- CategoryIdentifier.of(Firmament.MOD_ID, "forge_recipe")
+ object Category : DisplayCategory<SBForgeRecipe> {
+ override fun getCategoryIdentifier(): CategoryIdentifier<SBForgeRecipe> =
+ CategoryIdentifier.of(Firmament.MOD_ID, "forge_recipe")
- override fun getTitle(): Text = Text.literal("Forge Recipes")
- override fun getDisplayHeight(): Int {
- return 104
- }
+ override fun getTitle(): Text = Text.literal("Forge Recipes")
+ override fun getDisplayHeight(): Int {
+ return 104
+ }
- override fun getIcon(): Renderer = EntryStacks.of(Blocks.ANVIL)
- override fun setupDisplay(display: SBForgeRecipe, bounds: Rectangle): List<Widget> {
- return buildList {
- add(Widgets.createRecipeBase(bounds))
- add(Widgets.createResultSlotBackground(Point(bounds.minX + 124, bounds.minY + 46)))
- val arrow = Widgets.createArrow(Point(bounds.minX + 90, bounds.minY + 54 - 18 / 2))
- add(arrow)
- add(Widgets.createTooltip(arrow.bounds, Text.stringifiedTranslatable("firmament.recipe.forge.time", display.neuRecipe.duration.seconds)))
- val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
- val count = display.neuRecipe.inputs.size
- if (count == 1) {
- add(
- Widgets.createSlot(Point(ingredientsCenter.x, ingredientsCenter.y)).markInput()
- .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.inputs.single()))
- )
- } else {
- display.neuRecipe.inputs.forEachIndexed { idx, ingredient ->
- val rad = Math.PI * 2 * idx / count
- add(
- Widgets.createSlot(
- Point(
- cos(rad) * 30,
- sin(rad) * 30,
- ) + ingredientsCenter
- ).markInput().entry(SBItemEntryDefinition.getEntry(ingredient))
- )
- }
- }
- add(
- Widgets.createSlot(Point(bounds.minX + 124, bounds.minY + 46)).markOutput().disableBackground()
- .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.outputStack))
- )
- }
- }
- }
+ override fun getIcon(): Renderer = EntryStacks.of(Blocks.ANVIL)
+ override fun setupDisplay(display: SBForgeRecipe, bounds: Rectangle): List<Widget> {
+ return buildList {
+ add(Widgets.createRecipeBase(bounds))
+ add(Widgets.createResultSlotBackground(Point(bounds.minX + 124, bounds.minY + 46)))
+ val arrow = Widgets.createArrow(Point(bounds.minX + 90, bounds.minY + 54 - 18 / 2))
+ add(arrow)
+ add(Widgets.createTooltip(arrow.bounds,
+ Text.stringifiedTranslatable("firmament.recipe.forge.time",
+ display.neuRecipe.duration.seconds)))
+ val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
+ val count = display.neuRecipe.inputs.size
+ if (count == 1) {
+ add(
+ Widgets.createSlot(Point(ingredientsCenter.x, ingredientsCenter.y)).markInput()
+ .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.inputs.single()))
+ )
+ } else {
+ display.neuRecipe.inputs.forEachIndexed { idx, ingredient ->
+ val rad = Math.PI * 2 * idx / count
+ add(
+ Widgets.createSlot(
+ Point(
+ cos(rad) * 30,
+ sin(rad) * 30,
+ ) + ingredientsCenter
+ ).markInput().entry(SBItemEntryDefinition.getEntry(ingredient))
+ )
+ }
+ }
+ add(
+ Widgets.createSlot(Point(bounds.minX + 124, bounds.minY + 46)).markOutput().disableBackground()
+ .entry(SBItemEntryDefinition.getEntry(display.neuRecipe.outputStack))
+ )
+ }
+ }
+ }
}
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBKatRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBKatRecipe.kt
index fc77fa6..bafbdcc 100644
--- 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
@@ -1,4 +1,3 @@
-
package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUKatUpgradeRecipe
@@ -20,7 +19,6 @@ 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
@@ -34,191 +32,191 @@ import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId
class SBKatRecipe(override val neuRecipe: NEUKatUpgradeRecipe) : SBRecipe() {
- override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier
-
- object Category : DisplayCategory<SBKatRecipe> {
- override fun getCategoryIdentifier(): CategoryIdentifier<SBKatRecipe> =
- CategoryIdentifier.of(Firmament.MOD_ID, "kat_recipe")
-
- override fun getTitle(): Text = Text.literal("Kat Pet Upgrade")
- override fun getDisplayHeight(): Int {
- return 100
- }
-
- override fun getIcon(): Renderer = EntryStacks.of(Items.BONE)
- override fun setupDisplay(display: SBKatRecipe, bounds: Rectangle): List<Widget> {
- return buildList {
- val arrowWidth = 24
- val recipe = display.neuRecipe
- val levelValue = Property.upgrade(GetSetter.floating(0F))
- val slider = SliderComponent(levelValue, 1F, 100F, 1f, 100)
- val outputStack = SBItemStack(SkyblockId(recipe.output.itemId))
- val inputStack = SBItemStack(SkyblockId(recipe.input.itemId))
- val inputLevelLabelCenter = Point(bounds.minX + 30 - 18 + 5 + 8, bounds.minY + 25)
- val inputLevelLabel = Widgets.createLabel(
- inputLevelLabelCenter,
- Text.literal("")).centered()
- val outputLevelLabelCenter = Point(bounds.maxX - 30 + 8, bounds.minY + 25)
- val outputLevelLabel = Widgets.createLabel(
- outputLevelLabelCenter,
- Text.literal("")).centered()
- val coinStack = SBItemStack(SkyblockId.COINS, recipe.coins.toInt())
- levelValue.whenChanged { oldValue, newValue ->
- if (oldValue.toInt() == newValue.toInt()) return@whenChanged
- val oldInput = inputStack.getPetData() ?: return@whenChanged
- val newInput = PetData.forLevel(oldInput.petId, oldInput.rarity, newValue.toInt())
- inputStack.setPetData(newInput)
- val oldOutput = outputStack.getPetData() ?: return@whenChanged
- val newOutput = PetData(oldOutput.rarity, oldOutput.petId, newInput.exp)
- outputStack.setPetData(newOutput)
- inputLevelLabel.message = Text.literal(newInput.levelData.currentLevel.toString())
- inputLevelLabel.bounds.location = Point(
- inputLevelLabelCenter.x - MC.font.getWidth(inputLevelLabel.message) / 2,
- inputLevelLabelCenter.y)
- outputLevelLabel.message = Text.literal(newOutput.levelData.currentLevel.toString())
- outputLevelLabel.bounds.location = Point(
- outputLevelLabelCenter.x - MC.font.getWidth(outputLevelLabel.message) / 2,
- outputLevelLabelCenter.y)
- coinStack.setStackSize((recipe.coins * (1 - 0.3 * newValue / 100)).toInt())
- }
- levelValue.set(1F)
- add(Widgets.createRecipeBase(bounds))
- add(wrapWidget(Rectangle(bounds.centerX - slider.width / 2,
- bounds.maxY - 30,
- slider.width,
- slider.height),
- slider))
- add(Widgets.withTooltip(
- Widgets.createArrow(Point(bounds.centerX - arrowWidth / 2, bounds.minY + 40)),
- Text.literal("Upgrade time: " + FirmFormatters.formatTimespan(recipe.seconds.seconds))))
-
- add(Widgets.createResultSlotBackground(Point(bounds.maxX - 30, bounds.minY + 40)))
- add(inputLevelLabel)
- add(outputLevelLabel)
- add(Widgets.createSlot(Point(bounds.maxX - 30, bounds.minY + 40)).markOutput().disableBackground()
- .entry(SBItemEntryDefinition.getEntry(outputStack)))
- add(Widgets.createSlot(Point(bounds.minX + 30 - 18 + 5, bounds.minY + 40)).markInput()
- .entry(SBItemEntryDefinition.getEntry(inputStack)))
-
- val allInputs = recipe.items.map { SBItemEntryDefinition.getEntry(it) } +
- listOf(SBItemEntryDefinition.getEntry(coinStack))
- for ((index, item) in allInputs.withIndex()) {
- add(Widgets.createSlot(
- Point(bounds.centerX + index * 20 - allInputs.size * 18 / 2 - (allInputs.size - 1) * 2 / 2,
- bounds.minY + 20))
- .markInput()
- .entry(item))
- }
- }
- }
- }
+ override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier
+
+ object Category : DisplayCategory<SBKatRecipe> {
+ override fun getCategoryIdentifier(): CategoryIdentifier<SBKatRecipe> =
+ CategoryIdentifier.of(Firmament.MOD_ID, "kat_recipe")
+
+ override fun getTitle(): Text = Text.literal("Kat Pet Upgrade")
+ override fun getDisplayHeight(): Int {
+ return 100
+ }
+
+ override fun getIcon(): Renderer = EntryStacks.of(Items.BONE)
+ override fun setupDisplay(display: SBKatRecipe, bounds: Rectangle): List<Widget> {
+ return buildList {
+ val arrowWidth = 24
+ val recipe = display.neuRecipe
+ val levelValue = Property.upgrade(GetSetter.floating(0F))
+ val slider = SliderComponent(levelValue, 1F, 100F, 1f, 100)
+ val outputStack = SBItemStack(SkyblockId(recipe.output.itemId))
+ val inputStack = SBItemStack(SkyblockId(recipe.input.itemId))
+ val inputLevelLabelCenter = Point(bounds.minX + 30 - 18 + 5 + 8, bounds.minY + 25)
+ val inputLevelLabel = Widgets.createLabel(
+ inputLevelLabelCenter,
+ Text.literal("")).centered()
+ val outputLevelLabelCenter = Point(bounds.maxX - 30 + 8, bounds.minY + 25)
+ val outputLevelLabel = Widgets.createLabel(
+ outputLevelLabelCenter,
+ Text.literal("")).centered()
+ val coinStack = SBItemStack(SkyblockId.COINS, recipe.coins.toInt())
+ levelValue.whenChanged { oldValue, newValue ->
+ if (oldValue.toInt() == newValue.toInt()) return@whenChanged
+ val oldInput = inputStack.getPetData() ?: return@whenChanged
+ val newInput = PetData.forLevel(oldInput.petId, oldInput.rarity, newValue.toInt())
+ inputStack.setPetData(newInput)
+ val oldOutput = outputStack.getPetData() ?: return@whenChanged
+ val newOutput = PetData(oldOutput.rarity, oldOutput.petId, newInput.exp)
+ outputStack.setPetData(newOutput)
+ inputLevelLabel.message = Text.literal(newInput.levelData.currentLevel.toString())
+ inputLevelLabel.bounds.location = Point(
+ inputLevelLabelCenter.x - MC.font.getWidth(inputLevelLabel.message) / 2,
+ inputLevelLabelCenter.y)
+ outputLevelLabel.message = Text.literal(newOutput.levelData.currentLevel.toString())
+ outputLevelLabel.bounds.location = Point(
+ outputLevelLabelCenter.x - MC.font.getWidth(outputLevelLabel.message) / 2,
+ outputLevelLabelCenter.y)
+ coinStack.setStackSize((recipe.coins * (1 - 0.3 * newValue / 100)).toInt())
+ }
+ levelValue.set(1F)
+ add(Widgets.createRecipeBase(bounds))
+ add(wrapWidget(Rectangle(bounds.centerX - slider.width / 2,
+ bounds.maxY - 30,
+ slider.width,
+ slider.height),
+ slider))
+ add(Widgets.withTooltip(
+ Widgets.createArrow(Point(bounds.centerX - arrowWidth / 2, bounds.minY + 40)),
+ Text.literal("Upgrade time: " + FirmFormatters.formatTimespan(recipe.seconds.seconds))))
+
+ add(Widgets.createResultSlotBackground(Point(bounds.maxX - 30, bounds.minY + 40)))
+ add(inputLevelLabel)
+ add(outputLevelLabel)
+ add(Widgets.createSlot(Point(bounds.maxX - 30, bounds.minY + 40)).markOutput().disableBackground()
+ .entry(SBItemEntryDefinition.getEntry(outputStack)))
+ add(Widgets.createSlot(Point(bounds.minX + 30 - 18 + 5, bounds.minY + 40)).markInput()
+ .entry(SBItemEntryDefinition.getEntry(inputStack)))
+
+ val allInputs = recipe.items.map { SBItemEntryDefinition.getEntry(it) } +
+ listOf(SBItemEntryDefinition.getEntry(coinStack))
+ for ((index, item) in allInputs.withIndex()) {
+ add(Widgets.createSlot(
+ Point(bounds.centerX + index * 20 - allInputs.size * 18 / 2 - (allInputs.size - 1) * 2 / 2,
+ bounds.minY + 20))
+ .markInput()
+ .entry(item))
+ }
+ }
+ }
+ }
}
fun wrapWidget(bounds: Rectangle, component: GuiComponent): Widget {
- return object : WidgetWithBounds() {
- override fun getBounds(): Rectangle {
- return bounds
- }
-
- override fun children(): List<Element> {
- return listOf()
- }
-
- override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
- context.matrices.push()
- context.matrices.translate(bounds.minX.toFloat(), bounds.minY.toFloat(), 0F)
- component.render(
- GuiImmediateContext(
- ModernRenderContext(context),
- bounds.minX, bounds.minY,
- bounds.width, bounds.height,
- mouseX - bounds.minX, mouseY - bounds.minY,
- mouseX, mouseY,
- mouseX.toFloat(), mouseY.toFloat()
- ))
- context.matrices.pop()
- }
-
- override fun mouseMoved(mouseX: Double, mouseY: Double) {
- val mouseXInt = mouseX.toInt()
- val mouseYInt = mouseY.toInt()
- component.mouseEvent(MouseEvent.Move(0F, 0F),
- GuiImmediateContext(
- IMinecraft.instance.provideTopLevelRenderContext(),
- bounds.minX, bounds.minY,
- bounds.width, bounds.height,
- mouseXInt - bounds.minX, mouseYInt - bounds.minY,
- mouseXInt, mouseYInt,
- mouseX.toFloat(), mouseY.toFloat()
- ))
- }
-
- override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
- val mouseXInt = mouseX.toInt()
- val mouseYInt = mouseY.toInt()
- return component.mouseEvent(MouseEvent.Click(button, true),
- GuiImmediateContext(
- IMinecraft.instance.provideTopLevelRenderContext(),
- bounds.minX, bounds.minY,
- bounds.width, bounds.height,
- mouseXInt - bounds.minX, mouseYInt - bounds.minY,
- mouseXInt, mouseYInt,
- mouseX.toFloat(), mouseY.toFloat()
- ))
- }
-
- override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
- val mouseXInt = mouseX.toInt()
- val mouseYInt = mouseY.toInt()
- return component.mouseEvent(MouseEvent.Click(button, false),
- GuiImmediateContext(
- IMinecraft.instance.provideTopLevelRenderContext(),
- bounds.minX, bounds.minY,
- bounds.width, bounds.height,
- mouseXInt - bounds.minX, mouseYInt - bounds.minY,
- mouseXInt, mouseYInt,
- mouseX.toFloat(), mouseY.toFloat()
- ))
- }
-
- override fun mouseDragged(
- mouseX: Double,
- mouseY: Double,
- button: Int,
- deltaX: Double,
- deltaY: Double
- ): Boolean {
- val mouseXInt = mouseX.toInt()
- val mouseYInt = mouseY.toInt()
- return component.mouseEvent(MouseEvent.Move(deltaX.toFloat(), deltaY.toFloat()),
- GuiImmediateContext(
- IMinecraft.instance.provideTopLevelRenderContext(),
- bounds.minX, bounds.minY,
- bounds.width, bounds.height,
- mouseXInt - bounds.minX, mouseYInt - bounds.minY,
- mouseXInt, mouseYInt,
- mouseX.toFloat(), mouseY.toFloat()
- ))
-
- }
-
- override fun mouseScrolled(
- mouseX: Double,
- mouseY: Double,
- horizontalAmount: Double,
- verticalAmount: Double
- ): Boolean {
- val mouseXInt = mouseX.toInt()
- val mouseYInt = mouseY.toInt()
- return component.mouseEvent(MouseEvent.Scroll(verticalAmount.toFloat()),
- GuiImmediateContext(
- IMinecraft.instance.provideTopLevelRenderContext(),
- bounds.minX, bounds.minY,
- bounds.width, bounds.height,
- mouseXInt - bounds.minX, mouseYInt - bounds.minY,
- mouseXInt, mouseYInt,
- mouseX.toFloat(), mouseY.toFloat()
- ))
- }
- }
+ return object : WidgetWithBounds() {
+ override fun getBounds(): Rectangle {
+ return bounds
+ }
+
+ override fun children(): List<Element> {
+ return listOf()
+ }
+
+ override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
+ context.matrices.push()
+ context.matrices.translate(bounds.minX.toFloat(), bounds.minY.toFloat(), 0F)
+ component.render(
+ GuiImmediateContext(
+ ModernRenderContext(context),
+ bounds.minX, bounds.minY,
+ bounds.width, bounds.height,
+ mouseX - bounds.minX, mouseY - bounds.minY,
+ mouseX, mouseY,
+ mouseX.toFloat(), mouseY.toFloat()
+ ))
+ context.matrices.pop()
+ }
+
+ override fun mouseMoved(mouseX: Double, mouseY: Double) {
+ val mouseXInt = mouseX.toInt()
+ val mouseYInt = mouseY.toInt()
+ component.mouseEvent(MouseEvent.Move(0F, 0F),
+ GuiImmediateContext(
+ IMinecraft.instance.provideTopLevelRenderContext(),
+ bounds.minX, bounds.minY,
+ bounds.width, bounds.height,
+ mouseXInt - bounds.minX, mouseYInt - bounds.minY,
+ mouseXInt, mouseYInt,
+ mouseX.toFloat(), mouseY.toFloat()
+ ))
+ }
+
+ override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
+ val mouseXInt = mouseX.toInt()
+ val mouseYInt = mouseY.toInt()
+ return component.mouseEvent(MouseEvent.Click(button, true),
+ GuiImmediateContext(
+ IMinecraft.instance.provideTopLevelRenderContext(),
+ bounds.minX, bounds.minY,
+ bounds.width, bounds.height,
+ mouseXInt - bounds.minX, mouseYInt - bounds.minY,
+ mouseXInt, mouseYInt,
+ mouseX.toFloat(), mouseY.toFloat()
+ ))
+ }
+
+ override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
+ val mouseXInt = mouseX.toInt()
+ val mouseYInt = mouseY.toInt()
+ return component.mouseEvent(MouseEvent.Click(button, false),
+ GuiImmediateContext(
+ IMinecraft.instance.provideTopLevelRenderContext(),
+ bounds.minX, bounds.minY,
+ bounds.width, bounds.height,
+ mouseXInt - bounds.minX, mouseYInt - bounds.minY,
+ mouseXInt, mouseYInt,
+ mouseX.toFloat(), mouseY.toFloat()
+ ))
+ }
+
+ override fun mouseDragged(
+ mouseX: Double,
+ mouseY: Double,
+ button: Int,
+ deltaX: Double,
+ deltaY: Double
+ ): Boolean {
+ val mouseXInt = mouseX.toInt()
+ val mouseYInt = mouseY.toInt()
+ return component.mouseEvent(MouseEvent.Move(deltaX.toFloat(), deltaY.toFloat()),
+ GuiImmediateContext(
+ IMinecraft.instance.provideTopLevelRenderContext(),
+ bounds.minX, bounds.minY,
+ bounds.width, bounds.height,
+ mouseXInt - bounds.minX, mouseYInt - bounds.minY,
+ mouseXInt, mouseYInt,
+ mouseX.toFloat(), mouseY.toFloat()
+ ))
+
+ }
+
+ override fun mouseScrolled(
+ mouseX: Double,
+ mouseY: Double,
+ horizontalAmount: Double,
+ verticalAmount: Double
+ ): Boolean {
+ val mouseXInt = mouseX.toInt()
+ val mouseYInt = mouseY.toInt()
+ return component.mouseEvent(MouseEvent.Scroll(verticalAmount.toFloat()),
+ GuiImmediateContext(
+ IMinecraft.instance.provideTopLevelRenderContext(),
+ bounds.minX, bounds.minY,
+ bounds.width, bounds.height,
+ mouseXInt - bounds.minX, mouseYInt - bounds.minY,
+ mouseXInt, mouseYInt,
+ mouseX.toFloat(), mouseY.toFloat()
+ ))
+ }
+ }
}
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBMobDropRecipe.kt
index cb240fc..81ec41b 100644
--- 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
@@ -1,4 +1,3 @@
-
package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUMobDropRecipe
@@ -14,95 +13,95 @@ 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
+import moe.nea.firmament.gui.entity.EntityRenderer
class SBMobDropRecipe(override val neuRecipe: NEUMobDropRecipe) : SBRecipe() {
- override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier
+ override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier
- object Category : DisplayCategory<SBMobDropRecipe> {
- override fun getCategoryIdentifier(): CategoryIdentifier<SBMobDropRecipe> =
- CategoryIdentifier.of(Firmament.MOD_ID, "mob_drop_recipe")
+ object Category : DisplayCategory<SBMobDropRecipe> {
+ override fun getCategoryIdentifier(): CategoryIdentifier<SBMobDropRecipe> =
+ CategoryIdentifier.of(Firmament.MOD_ID, "mob_drop_recipe")
- override fun getTitle(): Text = Text.literal("Mob Drops")
- override fun getDisplayHeight(): Int {
- return 100
- }
+ override fun getTitle(): Text = Text.literal("Mob Drops")
+ override fun getDisplayHeight(): Int {
+ return 100
+ }
- override fun getIcon(): Renderer = EntryStacks.of(Items.DIAMOND_SWORD)
- override fun setupDisplay(display: SBMobDropRecipe, bounds: Rectangle): List<Widget> {
- return buildList {
- add(Widgets.createRecipeBase(bounds))
- val source = display.neuRecipe.render
- val entity = if (source.startsWith("@")) {
- EntityRenderer.constructEntity(Identifier.of(source.substring(1)))
- } else {
- EntityRenderer.applyModifiers(source, listOf())
- }
- if (entity != null) {
- val level = display.neuRecipe.level
- val fullMobName =
- if (level > 0) Text.translatable("firmament.recipe.mobs.name", level, display.neuRecipe.name)
- else Text.translatable("firmament.recipe.mobs.name.nolevel", display.neuRecipe.name)
- val tt = mutableListOf<Text>()
- tt.add((fullMobName))
- tt.add(Text.literal(""))
- if (display.neuRecipe.coins > 0) {
- tt.add(Text.stringifiedTranslatable("firmament.recipe.mobs.coins", display.neuRecipe.coins))
- }
- if (display.neuRecipe.combatExperience > 0) {
- tt.add(
- Text.stringifiedTranslatable(
- "firmament.recipe.mobs.combat",
- display.neuRecipe.combatExperience
- )
- )
- }
- if (display.neuRecipe.enchantingExperience > 0) {
- tt.add(
- Text.stringifiedTranslatable(
- "firmament.recipe.mobs.exp",
- display.neuRecipe.enchantingExperience
- )
- )
- }
- if (display.neuRecipe.extra != null)
- display.neuRecipe.extra.mapTo(tt) { Text.literal(it) }
- if (tt.size == 2)
- tt.removeAt(1)
- add(
- Widgets.withTooltip(
- EntityWidget(entity, Point(bounds.minX + 5, bounds.minY + 15)),
- tt
- )
- )
- }
- add(
- Widgets.createLabel(Point(bounds.minX + 15, bounds.minY + 5), Text.literal(display.neuRecipe.name))
- .leftAligned()
- )
- var x = bounds.minX + 60
- var y = bounds.minY + 20
- for (drop in display.neuRecipe.drops) {
- val lore = drop.extra.mapTo(mutableListOf()) { Text.literal(it) }
- if (drop.chance != null) {
- lore += listOf(Text.translatable("firmament.recipe.mobs.drops", drop.chance))
- }
- val item = SBItemEntryDefinition.getEntry(drop.dropItem)
- .value.copy(extraLore = lore)
- add(
- Widgets.createSlot(Point(x, y)).markOutput()
- .entries(listOf(SBItemEntryDefinition.getEntry(item)))
- )
- x += 18
- if (x > bounds.maxX - 30) {
- x = bounds.minX + 60
- y += 18
- }
- }
- }
- }
- }
+ override fun getIcon(): Renderer = EntryStacks.of(Items.DIAMOND_SWORD)
+ override fun setupDisplay(display: SBMobDropRecipe, bounds: Rectangle): List<Widget> {
+ return buildList {
+ add(Widgets.createRecipeBase(bounds))
+ val source = display.neuRecipe.render
+ val entity = if (source.startsWith("@")) {
+ EntityRenderer.constructEntity(Identifier.of(source.substring(1)))
+ } else {
+ EntityRenderer.applyModifiers(source, listOf())
+ }
+ if (entity != null) {
+ val level = display.neuRecipe.level
+ val fullMobName =
+ if (level > 0) Text.translatable("firmament.recipe.mobs.name", level, display.neuRecipe.name)
+ else Text.translatable("firmament.recipe.mobs.name.nolevel", display.neuRecipe.name)
+ val tt = mutableListOf<Text>()
+ tt.add((fullMobName))
+ tt.add(Text.literal(""))
+ if (display.neuRecipe.coins > 0) {
+ tt.add(Text.stringifiedTranslatable("firmament.recipe.mobs.coins", display.neuRecipe.coins))
+ }
+ if (display.neuRecipe.combatExperience > 0) {
+ tt.add(
+ Text.stringifiedTranslatable(
+ "firmament.recipe.mobs.combat",
+ display.neuRecipe.combatExperience
+ )
+ )
+ }
+ if (display.neuRecipe.enchantingExperience > 0) {
+ tt.add(
+ Text.stringifiedTranslatable(
+ "firmament.recipe.mobs.exp",
+ display.neuRecipe.enchantingExperience
+ )
+ )
+ }
+ if (display.neuRecipe.extra != null)
+ display.neuRecipe.extra.mapTo(tt) { Text.literal(it) }
+ if (tt.size == 2)
+ tt.removeAt(1)
+ add(
+ Widgets.withTooltip(
+ EntityWidget(entity, Point(bounds.minX + 5, bounds.minY + 15)),
+ tt
+ )
+ )
+ }
+ add(
+ Widgets.createLabel(Point(bounds.minX + 15, bounds.minY + 5), Text.literal(display.neuRecipe.name))
+ .leftAligned()
+ )
+ var x = bounds.minX + 60
+ var y = bounds.minY + 20
+ for (drop in display.neuRecipe.drops) {
+ val lore = drop.extra.mapTo(mutableListOf()) { Text.literal(it) }
+ if (drop.chance != null) {
+ lore += listOf(Text.translatable("firmament.recipe.mobs.drops", drop.chance))
+ }
+ val item = SBItemEntryDefinition.getEntry(drop.dropItem)
+ .value.copy(extraLore = lore)
+ add(
+ Widgets.createSlot(Point(x, y)).markOutput()
+ .entries(listOf(SBItemEntryDefinition.getEntry(item)))
+ )
+ x += 18
+ if (x > bounds.maxX - 30) {
+ x = bounds.minX + 60
+ y += 18
+ }
+ }
+ }
+ }
+ }
}
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBRecipe.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/recipes/SBRecipe.kt
index a66a529..de7779f 100644
--- 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
@@ -2,28 +2,41 @@ package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUIngredient
import io.github.moulberry.repo.data.NEURecipe
+import java.util.Optional
import me.shedaniel.rei.api.common.display.Display
+import me.shedaniel.rei.api.common.display.DisplaySerializer
import me.shedaniel.rei.api.common.entry.EntryIngredient
+import net.minecraft.util.Identifier
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<EntryIngredient> {
- return neuRecipe.allInputs
- .filter { it.itemId != NEUIngredient.NEU_SENTINEL_EMPTY }
- .map {
- val entryStack = SBItemEntryDefinition.getEntry(SkyblockId(it.itemId))
- EntryIngredient.of(entryStack)
- }
- }
+ override fun getDisplayLocation(): Optional<Identifier> {
+ // In theory, we could return a location for the neuRecipe here. (Something along the lines of neurepo:items/item_id.json/0 for the 0th recipe in the items/item_id.json recipes array).
+ return Optional.empty()
+ }
- override fun getOutputEntries(): List<EntryIngredient> {
- return neuRecipe.allOutputs
- .filter { it.itemId != NEUIngredient.NEU_SENTINEL_EMPTY }
- .map {
- val entryStack = SBItemEntryDefinition.getEntry(SkyblockId(it.itemId))
- EntryIngredient.of(entryStack)
- }
- }
+ override fun getSerializer(): DisplaySerializer<out Display>? {
+ // While returning null here is discouraged, we are fine to do so, since this recipe will never travel through the network
+ return null
+ }
+
+ abstract val neuRecipe: NEURecipe
+ override fun getInputEntries(): List<EntryIngredient> {
+ return neuRecipe.allInputs
+ .filter { it.itemId != NEUIngredient.NEU_SENTINEL_EMPTY }
+ .map {
+ val entryStack = SBItemEntryDefinition.getEntry(SkyblockId(it.itemId))
+ EntryIngredient.of(entryStack)
+ }
+ }
+
+ override fun getOutputEntries(): List<EntryIngredient> {
+ return neuRecipe.allOutputs
+ .filter { it.itemId != NEUIngredient.NEU_SENTINEL_EMPTY }
+ .map {
+ val entryStack = SBItemEntryDefinition.getEntry(SkyblockId(it.itemId))
+ EntryIngredient.of(entryStack)
+ }
+ }
}
diff --git a/src/compat/sodium/java/SodiumChunkReloader.kt b/src/compat/sodium/java/SodiumChunkReloader.kt
index 932c338..0256b88 100644
--- a/src/compat/sodium/java/SodiumChunkReloader.kt
+++ b/src/compat/sodium/java/SodiumChunkReloader.kt
@@ -1,6 +1,6 @@
package moe.nea.firmament.compat.sodium
-import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer
+import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer
import moe.nea.firmament.mixins.accessor.sodium.AccessorSodiumWorldRenderer
class SodiumChunkReloader : Runnable {
diff --git a/src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java b/src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java
index d585cbc..f75874d 100644
--- a/src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java
+++ b/src/compat/sodium/java/moe/nea/firmament/mixins/accessor/sodium/AccessorSodiumWorldRenderer.java
@@ -1,7 +1,7 @@
package moe.nea.firmament.mixins.accessor.sodium;
-import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer;
-import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager;
+import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer;
+import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.gen.Accessor;
@@ -9,6 +9,6 @@ import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(SodiumWorldRenderer.class)
@Pseudo
public interface AccessorSodiumWorldRenderer {
- @Accessor(value = "renderSectionManager", remap = false)
- RenderSectionManager getRenderSectionManager_firmament();
+ @Accessor(value = "renderSectionManager", remap = false)
+ RenderSectionManager getRenderSectionManager_firmament();
}
diff --git a/src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java b/src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java
index 90f20bc..fe87310 100644
--- a/src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java
+++ b/src/compat/sodium/java/moe/nea/firmament/mixins/custommodels/PatchBlockModelInSodiumChunkGenerator.java
@@ -3,8 +3,8 @@ package moe.nea.firmament.mixins.custommodels;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
-import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask;
import moe.nea.firmament.features.texturepack.CustomBlockTextures;
+import net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.block.BlockModels;
import net.minecraft.client.render.model.BakedModel;
@@ -15,7 +15,7 @@ import org.spongepowered.asm.mixin.injection.At;
@Mixin(ChunkBuilderMeshingTask.class)
public class PatchBlockModelInSodiumChunkGenerator {
@WrapOperation(
- method = "execute(Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lme/jellysquid/mods/sodium/client/util/task/CancellationToken;)Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;",
+ method = "execute(Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lnet/caffeinemc/mods/sodium/client/util/task/CancellationToken;)Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModels;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;"))
private BakedModel replaceBlockModel(BlockModels instance, BlockState state, Operation<BakedModel> original,
@Local(name = "blockPos") BlockPos.Mutable pos) {
diff --git a/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java b/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java
index 0f4d324..fde3580 100644
--- a/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/CustomDurabilityBarPatch.java
@@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.At;
@Mixin(DrawContext.class)
public class CustomDurabilityBarPatch {
@WrapOperation(
- method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V",
+ method = "drawItemBar",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isItemBarVisible()Z")
)
private boolean onIsItemBarVisible(
@@ -29,7 +29,7 @@ public class CustomDurabilityBarPatch {
return barOverride.get() != null;
}
- @WrapOperation(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V",
+ @WrapOperation(method = "drawItemBar",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarStep()I"))
private int overrideItemStep(
ItemStack instance, Operation<Integer> original,
@@ -40,7 +40,7 @@ public class CustomDurabilityBarPatch {
return original.call(instance);
}
- @WrapOperation(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V",
+ @WrapOperation(method = "drawItemBar",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarColor()I"))
private int overrideItemColor(
ItemStack instance, Operation<Integer> original,
diff --git a/src/main/java/moe/nea/firmament/mixins/CustomModelBakerPatch.java b/src/main/java/moe/nea/firmament/mixins/CustomModelBakerPatch.java
deleted file mode 100644
index c1e359d..0000000
--- a/src/main/java/moe/nea/firmament/mixins/CustomModelBakerPatch.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package moe.nea.firmament.mixins;
-
-import moe.nea.firmament.events.BakeExtraModelsEvent;
-import net.minecraft.client.render.model.ModelLoader;
-import net.minecraft.client.render.model.UnbakedModel;
-import net.minecraft.client.util.ModelIdentifier;
-import net.minecraft.util.Identifier;
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.Unique;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import java.util.Map;
-
-@Mixin(ModelLoader.class)
-public abstract class CustomModelBakerPatch {
-
- @Shadow
- @Final
- private Map<ModelIdentifier, UnbakedModel> modelsToBake;
-
- @Shadow
- protected abstract void loadItemModel(ModelIdentifier id);
-
- @Shadow
- abstract UnbakedModel getOrLoadModel(Identifier id);
-
- @Shadow
- protected abstract void add(ModelIdentifier id, UnbakedModel model);
-
- @Unique
- private void loadNonItemModel(ModelIdentifier identifier) {
- UnbakedModel unbakedModel = this.getOrLoadModel(identifier.id());
- this.add(identifier, unbakedModel);
- }
-
-
- @Inject(method = "bake", at = @At("HEAD"))
- public void onBake(ModelLoader.SpriteGetter spliteGetter, CallbackInfo ci) {
- BakeExtraModelsEvent.Companion.publish(new BakeExtraModelsEvent(this::loadItemModel, this::loadNonItemModel));
- modelsToBake.values().forEach(model -> model.setParents(this::getOrLoadModel));
-// modelsToBake.keySet().stream()
-// .filter(it -> !it.id().getNamespace().equals("minecraft"))
-// .forEach(it -> System.out.println("Non minecraft texture is being loaded: " + it));
- }
-}
diff --git a/src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java b/src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java
index 61fc82e..e7207f4 100644
--- a/src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/CustomModelEventPatch.java
@@ -7,6 +7,7 @@ import net.minecraft.client.render.item.ItemModels;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.item.ItemStack;
+import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -14,16 +15,15 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import java.util.Map;
+
@Mixin(ItemModels.class)
public class CustomModelEventPatch {
- @Shadow
- @Final
- private BakedModelManager modelManager;
- @Inject(method = "getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true)
- public void onGetModel(ItemStack stack, CallbackInfoReturnable<BakedModel> cir) {
- var model = CustomItemModelEvent.getModel(stack, modelManager);
- if (model != null)
- cir.setReturnValue(model);
- }
+ @Inject(method = "getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true)
+ public void onGetModel(ItemStack stack, CallbackInfoReturnable<BakedModel> cir) {
+ var model = CustomItemModelEvent.getModel(stack, (ItemModels) (Object) this);
+ if (model != null)
+ cir.setReturnValue(model);
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java b/src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java
index 4b3f3c3..f3b616a 100644
--- a/src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/CustomSkullTexturePatch.java
@@ -2,7 +2,6 @@
package moe.nea.firmament.mixins;
-import com.mojang.authlib.GameProfile;
import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures;
import net.minecraft.block.SkullBlock;
import net.minecraft.client.render.RenderLayer;
@@ -15,8 +14,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(SkullBlockEntityRenderer.class)
public class CustomSkullTexturePatch {
- @Inject(method = "getRenderLayer", at = @At("HEAD"), cancellable = true)
- private static void onGetRenderLayer(SkullBlock.SkullType type, ProfileComponent profile, CallbackInfoReturnable<RenderLayer> cir) {
- CustomSkyBlockTextures.INSTANCE.modifySkullTexture(type, profile, cir);
- }
+ @Inject(method = "getRenderLayer", at = @At("HEAD"), cancellable = true)
+ private static void onGetRenderLayer(SkullBlock.SkullType type, ProfileComponent profile, CallbackInfoReturnable<RenderLayer> cir) {
+ CustomSkyBlockTextures.INSTANCE.modifySkullTexture(type, profile, cir);
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java b/src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java
index da04ca2..717d404 100644
--- a/src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/DFUEntityIdFixPatch.java
@@ -17,6 +17,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map;
+// TODO: rework this
@Mixin(EntityIdFix.class)
public abstract class DFUEntityIdFixPatch extends DataFix {
@Shadow
diff --git a/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java b/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java
deleted file mode 100644
index 5306e42..0000000
--- a/src/main/java/moe/nea/firmament/mixins/InjectCustomShaderPrograms.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package moe.nea.firmament.mixins;
-
-import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
-import com.llamalad7.mixinextras.sugar.Local;
-import com.mojang.datafixers.util.Pair;
-import moe.nea.firmament.events.RegisterCustomShadersEvent;
-import net.minecraft.client.gl.ShaderProgram;
-import net.minecraft.client.render.GameRenderer;
-import net.minecraft.resource.ResourceFactory;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import java.util.List;
-import java.util.function.Consumer;
-
-@Mixin(GameRenderer.class)
-public class InjectCustomShaderPrograms {
-
- @Inject(method = "loadPrograms",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;loadBlurPostProcessor(Lnet/minecraft/resource/ResourceFactory;)V",
- shift = At.Shift.AFTER))
- void addFirmamentShaders(
- ResourceFactory resourceFactory, CallbackInfo ci,
- @Local(index = 3) List<Pair<ShaderProgram, Consumer<ShaderProgram>>> list
- ) {
- var event = new RegisterCustomShadersEvent(list, resourceFactory);
- RegisterCustomShadersEvent.Companion.publish(event);
- }
-}
diff --git a/src/main/java/moe/nea/firmament/mixins/MainWindowFirstLoadPatch.java b/src/main/java/moe/nea/firmament/mixins/MainWindowFirstLoadPatch.java
new file mode 100644
index 0000000..0a90b35
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/MainWindowFirstLoadPatch.java
@@ -0,0 +1,31 @@
+package moe.nea.firmament.mixins;
+
+import moe.nea.firmament.Firmament;
+import moe.nea.firmament.events.DebugInstantiateEvent;
+import net.minecraft.client.gui.LogoDrawer;
+import net.minecraft.client.gui.screen.TitleScreen;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Unique;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(TitleScreen.class)
+public class MainWindowFirstLoadPatch {
+ @Unique
+ private static boolean hasInited = false;
+
+ @Inject(method = "<init>(ZLnet/minecraft/client/gui/LogoDrawer;)V", at = @At("RETURN"))
+ private void onCreate(boolean doBackgroundFade, LogoDrawer logoDrawer, CallbackInfo ci) {
+ if (!hasInited) {
+ try {
+ DebugInstantiateEvent.Companion.publish(new DebugInstantiateEvent());
+ } catch (Throwable t) {
+ Firmament.INSTANCE.getLogger().error("Failed to instantiate debug instances", t);
+ System.exit(1);
+ throw t;
+ }
+ }
+ hasInited = true;
+ }
+}
diff --git a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
index fd50c72..1034a12 100644
--- a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
+++ b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
@@ -2,6 +2,9 @@
package moe.nea.firmament.mixins;
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.events.*;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
@@ -21,6 +24,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
+import java.util.Iterator;
+
@Mixin(HandledScreen.class)
public abstract class MixinHandledScreen<T extends ScreenHandler> {
@@ -90,15 +95,12 @@ public abstract class MixinHandledScreen<T extends ScreenHandler> {
}
- @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD)
- public void onAfterDrawSlot(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci, int i, int j, int k, Slot slot) {
- SlotRenderEvents.After event = new SlotRenderEvents.After(context, slot, mouseX, mouseY, delta);
- SlotRenderEvents.After.Companion.publish(event);
- }
-
- @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD)
- public void onBeforeDrawSlot(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci, int i, int j, int k, Slot slot) {
- SlotRenderEvents.Before event = new SlotRenderEvents.Before(context, slot, mouseX, mouseY, delta);
- SlotRenderEvents.Before.Companion.publish(event);
+ @WrapOperation(method = "drawSlots", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V"))
+ public void onDrawSlots(HandledScreen instance, DrawContext context, Slot slot, Operation<Void> original) {
+ var before = new SlotRenderEvents.Before(context, slot);
+ SlotRenderEvents.Before.Companion.publish(before);
+ original.call(instance, context, slot);
+ var after = new SlotRenderEvents.After(context, slot);
+ SlotRenderEvents.After.Companion.publish(after);
}
}
diff --git a/src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java
index 190fda0..c9fb073 100644
--- a/src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java
+++ b/src/main/java/moe/nea/firmament/mixins/ReplaceTextColorInHandledScreen.java
@@ -20,12 +20,16 @@ import org.spongepowered.asm.mixin.injection.At;
AnvilScreen.class, BeaconScreen.class})
public class ReplaceTextColorInHandledScreen {
+ // To my future self: double check those mixins, but don't be too concerned about errors. Some of the wrapopertions
+ // only apply in some of the specified subclasses.
+
@WrapOperation(
method = "drawForeground",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/gui/DrawContext;drawText(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;IIIZ)I"),
- expect = 0)
+ expect = 0,
+ require = 0)
private int replaceTextColorWithVariableShadow(DrawContext instance, TextRenderer textRenderer, Text text, int x, int y, int color, boolean shadow, Operation<Integer> original) {
return original.call(instance, textRenderer, text, x, y, CustomTextColors.INSTANCE.mapTextColor(text, color), shadow);
}
@@ -35,7 +39,8 @@ public class ReplaceTextColorInHandledScreen {
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/gui/DrawContext;drawTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;III)I"),
- expect = 0)
+ expect = 0,
+ require = 0)
private int replaceTextColorWithShadow(DrawContext instance, TextRenderer textRenderer, Text text, int x, int y, int color, Operation<Integer> original) {
return original.call(instance, textRenderer, text, x, y, CustomTextColors.INSTANCE.mapTextColor(text, color));
}
diff --git a/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java b/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java
index 6c854d4..06ecbd4 100644
--- a/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java
+++ b/src/main/java/moe/nea/firmament/mixins/SlotUpdateListener.java
@@ -23,14 +23,13 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler {
@Inject(
method = "onScreenHandlerSlotUpdate",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/tutorial/TutorialManager;onSlotUpdate(Lnet/minecraft/item/ItemStack;)V"))
+ at = @At(value = "TAIL"))
private void onSingleSlotUpdate(
ScreenHandlerSlotUpdateS2CPacket packet,
CallbackInfo ci) {
var player = this.client.player;
assert player != null;
- if (packet.getSyncId() == ScreenHandlerSlotUpdateS2CPacket.UPDATE_PLAYER_INVENTORY_SYNC_ID
- || packet.getSyncId() == 0) {
+ if (packet.getSyncId() == 0) {
PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Single(packet.getSlot(), packet.getStack()));
} else if (packet.getSyncId() == player.currentScreenHandler.syncId) {
ChestInventoryUpdateEvent.Companion.publish(
@@ -40,8 +39,7 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler {
}
@Inject(method = "onInventory",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V",
- shift = At.Shift.AFTER))
+ at = @At("TAIL"))
private void onMultiSlotUpdate(InventoryS2CPacket packet, CallbackInfo ci) {
var player = this.client.player;
assert player != null;
diff --git a/src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java b/src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java
index c444f12..d4b8c9e 100644
--- a/src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java
@@ -3,16 +3,17 @@
package moe.nea.firmament.mixins;
import moe.nea.firmament.events.WorldReadyEvent;
+import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-@Mixin(DownloadingTerrainScreen.class)
+@Mixin(MinecraftClient.class)
public class WorldReadyEventPatch {
- @Inject(method = "close", at = @At("HEAD"))
- public void onClose(CallbackInfo ci) {
- WorldReadyEvent.Companion.publish(new WorldReadyEvent());
- }
+ @Inject(method = "joinWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;setWorld(Lnet/minecraft/client/world/ClientWorld;)V", shift = At.Shift.AFTER))
+ public void onClose(CallbackInfo ci) {
+ WorldReadyEvent.Companion.publish(new WorldReadyEvent());
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java b/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java
index 2ff4560..847fb4d 100644
--- a/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/WorldRenderLastEventPatch.java
@@ -5,8 +5,10 @@ package moe.nea.firmament.mixins;
import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.events.WorldRenderLastEvent;
import net.minecraft.client.render.*;
+import net.minecraft.client.util.Handle;
+import net.minecraft.client.util.ObjectAllocator;
import net.minecraft.client.util.math.MatrixStack;
-import net.minecraft.world.tick.TickManager;
+import net.minecraft.util.profiler.Profiler;
import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -16,22 +18,30 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(WorldRenderer.class)
-public class WorldRenderLastEventPatch {
- @Shadow
- @Final
- private BufferBuilderStorage bufferBuilders;
+public abstract class WorldRenderLastEventPatch {
+ @Shadow
+ @Final
+ private BufferBuilderStorage bufferBuilders;
- @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;renderChunkDebugInfo(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/client/render/Camera;)V", shift = At.Shift.BEFORE))
- public void onWorldRenderLast(
- RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer,
- LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, Matrix4f matrix4f2,
- CallbackInfo ci, @Local MatrixStack matrixStack
- ) {
- var event = new WorldRenderLastEvent(
- matrixStack, tickCounter, renderBlockOutline,
- camera, gameRenderer, lightmapTextureManager,
- this.bufferBuilders.getEntityVertexConsumers()
- );
- WorldRenderLastEvent.Companion.publish(event);
- }
+ @Shadow
+ @Final
+ private DefaultFramebufferSet framebufferSet;
+
+ @Shadow
+ protected abstract void checkEmpty(MatrixStack matrices);
+
+ @Inject(method = "method_62214", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;pop()V", shift = At.Shift.AFTER))
+ public void onWorldRenderLast(Fog fog, RenderTickCounter tickCounter, Camera camera, Profiler profiler, Matrix4f matrix4f, Matrix4f matrix4f2, Handle handle, Handle handle2, Handle handle3, Handle handle4, boolean bl, Frustum frustum, Handle handle5, CallbackInfo ci) {
+ var imm = this.bufferBuilders.getEntityVertexConsumers();
+ var stack = new MatrixStack();
+ // TODO: pre-cancel this event if F1 is active
+ var event = new WorldRenderLastEvent(
+ stack, tickCounter,
+ camera,
+ imm
+ );
+ WorldRenderLastEvent.Companion.publish(event);
+ imm.draw();
+ checkEmpty(stack);
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorGameRenderer.java b/src/main/java/moe/nea/firmament/mixins/accessor/AccessorGameRenderer.java
deleted file mode 100644
index f5d2202..0000000
--- a/src/main/java/moe/nea/firmament/mixins/accessor/AccessorGameRenderer.java
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-package moe.nea.firmament.mixins.accessor;
-
-import net.minecraft.client.render.Camera;
-import net.minecraft.client.render.GameRenderer;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.gen.Invoker;
-
-@Mixin(GameRenderer.class)
-public interface AccessorGameRenderer {
- @Invoker("getFov")
- double getFov_firmament(Camera camera, float tickDelta, boolean changingFov);
-}
diff --git a/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java
index deac0a4..814f172 100644
--- a/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java
+++ b/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java
@@ -14,7 +14,6 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
-import net.minecraft.util.collection.DefaultedList;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -88,29 +87,18 @@ public class PatchHandledScreen<T extends ScreenHandler> extends Screen implemen
}
- @Unique
- private Slot didBeforeSlotRender;
-
@WrapOperation(
- method = "render",
+ method = "drawSlots",
at = @At(
value = "INVOKE",
- target = "Lnet/minecraft/util/collection/DefaultedList;get(I)Ljava/lang/Object;"))
- private Object beforeSlotRender(DefaultedList instance, int index, Operation<Object> original, @Local(argsOnly = true) DrawContext context) {
- var slot = (Slot) original.call(instance, index);
+ target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V"))
+ private void beforeSlotRender(HandledScreen instance, DrawContext context, Slot slot, Operation<Void> original) {
if (override != null) {
- didBeforeSlotRender = slot;
override.beforeSlotRender(context, slot);
}
- return slot;
- }
-
- @Inject(method = "render",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/util/collection/DefaultedList;size()I"))
- private void afterSlotRender(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) {
- if (override != null && didBeforeSlotRender != null) {
- override.afterSlotRender(context, didBeforeSlotRender);
- didBeforeSlotRender = null;
+ original.call(instance, context, slot);
+ if (override != null) {
+ override.afterSlotRender(context, slot);
}
}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java
index 64b358f..dac65fe 100644
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ApplyHeadModelInItemRenderer.java
@@ -1,33 +1,35 @@
package moe.nea.firmament.mixins.custommodels;
-import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
-import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
+import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import moe.nea.firmament.features.texturepack.BakedModelExtra;
+import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
-import net.minecraft.client.render.model.json.ModelTransformationMode;
-import net.minecraft.entity.LivingEntity;
+import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
-import net.minecraft.world.World;
+import net.minecraft.item.ModelTransformationMode;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemRenderer.class)
public class ApplyHeadModelInItemRenderer {
- @WrapOperation(method = "renderItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/world/World;III)V",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/ItemRenderer;getModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;I)Lnet/minecraft/client/render/model/BakedModel;"))
- private BakedModel applyHeadModel(ItemRenderer instance, ItemStack stack, World world, LivingEntity entity, int seed, Operation<BakedModel> original,
- @Local(argsOnly = true) ModelTransformationMode modelTransformationMode) {
- var model = original.call(instance, stack, world, entity, seed);
- if (modelTransformationMode == ModelTransformationMode.HEAD
- && model instanceof BakedModelExtra extra) {
- var headModel = extra.getHeadModel_firmament();
- if (headModel != null) {
- model = headModel;
- }
- }
- return model;
- }
+ @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V",
+ at = @At("HEAD"))
+ private void applyHeadModel(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded,
+ MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay,
+ BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci,
+ @Local(argsOnly = true) LocalRef<BakedModel> modelMut
+ ) {
+ var extra = BakedModelExtra.cast(model);
+ if (transformationMode == ModelTransformationMode.HEAD && extra != null) {
+ var headModel = extra.getHeadModel_firmament();
+ if (headModel != null) {
+ modelMut.set(headModel);
+ }
+ }
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java
index eee7557..c708862 100644
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/GlobalModelOverridePatch.java
@@ -8,6 +8,7 @@ import net.minecraft.client.render.model.BakedModel;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
+import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -17,13 +18,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ItemRenderer.class)
public abstract class GlobalModelOverridePatch {
- @Shadow
- public abstract ItemModels getModels();
+ @Shadow
+ @Final
+ private ItemModels models;
- @Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
- private void overrideGlobalModel(
- ItemStack stack, World world, LivingEntity entity,
- int seed, CallbackInfoReturnable<BakedModel> cir) {
- CustomGlobalTextures.replaceGlobalModel(this.getModels(), stack, cir);
- }
+ @Inject(method = "getModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;I)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true)
+ private void overrideGlobalModel(
+ ItemStack stack, World world, LivingEntity entity,
+ int seed, CallbackInfoReturnable<BakedModel> cir) {
+ CustomGlobalTextures.replaceGlobalModel(this.models, stack, cir);
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/HeadModelReplacerPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/HeadModelReplacerPatch.java
new file mode 100644
index 0000000..26c331e
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/HeadModelReplacerPatch.java
@@ -0,0 +1,57 @@
+
+package moe.nea.firmament.mixins.custommodels;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import com.llamalad7.mixinextras.sugar.Local;
+import moe.nea.firmament.features.texturepack.BakedModelExtra;
+import net.minecraft.block.AbstractSkullBlock;
+import net.minecraft.block.Block;
+import net.minecraft.block.Blocks;
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.LivingEntityRenderer;
+import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
+import net.minecraft.client.render.entity.model.EntityModel;
+import net.minecraft.client.render.entity.model.ModelWithHead;
+import net.minecraft.client.render.entity.state.LivingEntityRenderState;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.item.BlockItem;
+import net.minecraft.item.ItemStack;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+@Mixin(HeadFeatureRenderer.class)
+public class HeadModelReplacerPatch<S extends LivingEntityRenderState, M extends EntityModel<S> & ModelWithHead> {
+ /**
+ * This class serves to disable the replacing of head models with the vanilla block model. Vanilla first selects loads
+ * the model containing the head model regularly in {@link LivingEntityRenderer#updateRenderState}, but then discards
+ * the model in {@link HeadFeatureRenderer#render(MatrixStack, VertexConsumerProvider, int, LivingEntityRenderState, float, float)}
+ * if it detects a skull block. This serves to disable that functionality if a head model override is present.
+ */
+ @WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;getBlock()Lnet/minecraft/block/Block;"))
+ private Block replaceSkull(BlockItem instance, Operation<Block> original, @Local BakedModel bakedModel) {
+ var oldBlock = original.call(instance);
+ if (oldBlock instanceof AbstractSkullBlock) {
+ var extra = BakedModelExtra.cast(bakedModel);
+ if (extra != null && extra.getHeadModel_firmament() != null)
+ return Blocks.ENCHANTING_TABLE; // Any non skull block. Let's choose the enchanting table because it is very distinct.
+ }
+ return oldBlock;
+ }
+
+ /**
+ * We disable the has model override, since texture packs get precedent to server data.
+ */
+ @WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/feature/ArmorFeatureRenderer;hasModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/EquipmentSlot;)Z"))
+ private boolean replaceHasModel(ItemStack stack, EquipmentSlot slot, Operation<Boolean> original,
+ @Local BakedModel bakedModel) {
+ var extra = BakedModelExtra.cast(bakedModel);
+ if (extra != null && extra.getHeadModel_firmament() != null)
+ return false;
+ return original.call(stack, slot);
+ }
+}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java
index 5ed0fbe..8c5411b 100644
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java
@@ -5,28 +5,30 @@ import moe.nea.firmament.features.texturepack.TintOverrides;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
-import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
+import net.minecraft.item.ModelTransformationMode;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-@Mixin(ItemRenderer.class)
+@Mixin(value = ItemRenderer.class, priority = 1010)
public class ItemRendererTintContextPatch {
- @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/BakedModel;getTransformation()Lnet/minecraft/client/render/model/json/ModelTransformation;"), allow = 1)
- private void onStartRendering(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
- if (model instanceof BakedModelExtra extra) {
+ @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V",
+ at = @At(value = "HEAD"), allow = 1)
+ private void onStartRendering(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci) {
+ var extra = BakedModelExtra.cast(model);
+ if (extra != null) {
TintOverrides.Companion.enter(extra.getTintOverrides_firmament());
}
}
- @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;pop()V"), allow = 1)
- private void onEndRendering(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
- if (model instanceof BakedModelExtra extra) {
+ @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V",
+ at = @At("TAIL"), allow = 1)
+ private void onEndRendering(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci) {
+ var extra = BakedModelExtra.cast(model);
+ if (extra != null) {
TintOverrides.Companion.exit(extra.getTintOverrides_firmament());
}
}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java b/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java
index 20c69e2..a5bb34f 100644
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java
@@ -1,11 +1,11 @@
package moe.nea.firmament.mixins.custommodels;
-import com.google.gson.annotations.SerializedName;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.features.texturepack.BakedModelExtra;
import moe.nea.firmament.features.texturepack.JsonUnbakedModelFirmExtra;
import moe.nea.firmament.features.texturepack.TintOverrides;
+import moe.nea.firmament.util.ErrorUtil;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.Baker;
import net.minecraft.client.render.model.ModelRotation;
@@ -18,15 +18,20 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-import java.util.Collection;
import java.util.Objects;
@Mixin(JsonUnbakedModel.class)
-public class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra {
+public abstract class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra {
@Shadow
@Nullable
protected JsonUnbakedModel parent;
+
+ @Shadow
+ public abstract String toString();
+
@Unique
@Nullable
public Identifier headModel;
@@ -67,31 +72,59 @@ public class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra {
return ((JsonUnbakedModelFirmExtra) this.parent).getHeadModel_firmament();
}
- @ModifyReturnValue(method = "getModelDependencies", at = @At("RETURN"))
- private Collection<Identifier> addDependencies(Collection<Identifier> original) {
+ @Inject(method = "resolve", at = @At("HEAD"))
+ private void addDependencies(UnbakedModel.Resolver resolver, CallbackInfo ci) {
var headModel = getHeadModel_firmament();
if (headModel != null) {
- original.add(headModel);
+ resolver.resolve(headModel);
}
- return original;
}
- @ModifyReturnValue(
- method = "bake(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;",
- at = @At(value = "RETURN"))
- private BakedModel bakeExtraInfo(BakedModel original, @Local(argsOnly = true) Baker baker) {
- if (original instanceof BakedModelExtra extra) {
+ private void addExtraBakeInfo(BakedModel bakedModel, Baker baker) {
+ if (!this.toString().contains("minecraft") && this.toString().contains("crimson")) {
+ System.out.println("Found non minecraft model " + this);
+ }
+ var extra = BakedModelExtra.cast(bakedModel);
+ if (extra != null) {
var headModel = getHeadModel_firmament();
if (headModel != null) {
- UnbakedModel unbakedModel = baker.getOrLoadModel(headModel);
- extra.setHeadModel_firmament(
- Objects.equals(unbakedModel, parent)
- ? null
- : baker.bake(headModel, ModelRotation.X0_Y0));
+ extra.setHeadModel_firmament(baker.bake(headModel, ModelRotation.X0_Y0));
}
- if (getTintOverrides_firmament().hasOverrides())
+ if (getTintOverrides_firmament().hasOverrides()) {
extra.setTintOverrides_firmament(getTintOverrides_firmament());
+ }
+ }
+ }
+
+ /**
+ * @see ProvideBakerToJsonUnbakedModelPatch
+ */
+ @Override
+ public void storeExtraBaker_firmament(@NotNull Baker baker) {
+ this.storedBaker = baker;
+ }
+
+ @Unique
+ private Baker storedBaker;
+
+ @ModifyReturnValue(
+ method = "bake(Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;",
+ at = @At("RETURN"))
+ private BakedModel bakeExtraInfoWithoutBaker(BakedModel original) {
+ if (storedBaker != null) {
+ addExtraBakeInfo(original, storedBaker);
+ storedBaker = null;
}
return original;
}
+
+ @ModifyReturnValue(
+ method = {
+ "bake(Lnet/minecraft/client/render/model/Baker;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;"
+ },
+ at = @At(value = "RETURN"))
+ private BakedModel bakeExtraInfo(BakedModel original, @Local(argsOnly = true) Baker baker) {
+ addExtraBakeInfo(original, baker);
+ return original;
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java
index 7c6f69e..4468150 100644
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchArmorTexture.java
@@ -6,26 +6,24 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.features.texturepack.CustomGlobalArmorOverrides;
import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
-import net.minecraft.item.ArmorMaterial;
+import net.minecraft.component.type.EquippableComponent;
import net.minecraft.item.ItemStack;
+import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
-import java.util.List;
+import java.util.Optional;
@Mixin(ArmorFeatureRenderer.class)
public class PatchArmorTexture {
- @WrapOperation(
- method = "renderArmor",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ArmorMaterial;layers()Ljava/util/List;"))
- private List<ArmorMaterial.Layer> overrideLayers(
- ArmorMaterial instance,
- Operation<List<ArmorMaterial.Layer>> original,
- @Local ItemStack itemStack
- ) {
- var overrides = CustomGlobalArmorOverrides.overrideArmor(itemStack);
- if (overrides == null)
- return original.call(instance);
- return overrides;
- }
+ @WrapOperation(
+ method = "renderArmor",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/component/type/EquippableComponent;model()Ljava/util/Optional;"))
+ private Optional<Identifier> overrideLayers(
+ EquippableComponent instance, Operation<Optional<Identifier>> original, @Local(argsOnly = true) ItemStack itemStack
+ ) {
+ // TODO: check that all armour items are naturally equippable and have the equppable component. otherwise our call here will not be reached.
+ var overrides = CustomGlobalArmorOverrides.overrideArmor(itemStack);
+ return overrides.or(() -> original.call(instance));
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchHeadFeatureRenderer.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchHeadFeatureRenderer.java
deleted file mode 100644
index 610a106..0000000
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchHeadFeatureRenderer.java
+++ /dev/null
@@ -1,45 +0,0 @@
-
-package moe.nea.firmament.mixins.custommodels;
-
-import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
-import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
-import com.llamalad7.mixinextras.sugar.Local;
-import moe.nea.firmament.features.texturepack.BakedModelExtra;
-import net.minecraft.block.AbstractSkullBlock;
-import net.minecraft.block.Block;
-import net.minecraft.block.Blocks;
-import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
-import net.minecraft.client.render.entity.model.EntityModel;
-import net.minecraft.client.render.item.HeldItemRenderer;
-import net.minecraft.entity.LivingEntity;
-import net.minecraft.item.BlockItem;
-import net.minecraft.item.ItemStack;
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-
-@Mixin(HeadFeatureRenderer.class)
-public class PatchHeadFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> {
-
- @Shadow
- @Final
- private HeldItemRenderer heldItemRenderer;
-
- @WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/entity/LivingEntity;FFFFFF)V",
- at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;getBlock()Lnet/minecraft/block/Block;"))
- private Block replaceSkull(BlockItem instance, Operation<Block> original, @Local ItemStack itemStack, @Local(argsOnly = true) T entity) {
- var oldBlock = original.call(instance);
- if (oldBlock instanceof AbstractSkullBlock) {
- var bakedModel = this.heldItemRenderer.itemRenderer
- .getModel(itemStack, entity.getWorld(), entity, 0);
- if (bakedModel instanceof BakedModelExtra extra && extra.getHeadModel_firmament() != null)
- return Blocks.ENCHANTING_TABLE; // Any non skull block. Let's choose the enchanting table because it is very distinct.
- }
- return oldBlock;
- }
-
-
-
-
-}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchLegacyArmorLayerSupport.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchLegacyArmorLayerSupport.java
new file mode 100644
index 0000000..8c0b3f8
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchLegacyArmorLayerSupport.java
@@ -0,0 +1,22 @@
+package moe.nea.firmament.mixins.custommodels;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import moe.nea.firmament.features.texturepack.CustomGlobalArmorOverrides;
+import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
+import net.minecraft.client.render.entity.equipment.EquipmentRenderer;
+import net.minecraft.item.equipment.EquipmentModel;
+import net.minecraft.util.Identifier;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+@Mixin(EquipmentRenderer.class)
+public class PatchLegacyArmorLayerSupport {
+ @WrapOperation(method = "render(Lnet/minecraft/item/equipment/EquipmentModel$LayerType;Lnet/minecraft/util/Identifier;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V",
+ at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/equipment/EquipmentModelLoader;get(Lnet/minecraft/util/Identifier;)Lnet/minecraft/item/equipment/EquipmentModel;"))
+ private EquipmentModel patchModelLayers(EquipmentModelLoader instance, Identifier id, Operation<EquipmentModel> original) {
+ var modelOverride = CustomGlobalArmorOverrides.overrideArmorLayer(id);
+ if (modelOverride != null) return modelOverride;
+ return original.call(instance, id);
+ }
+}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java
index 938d14d..abb1792 100644
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java
@@ -22,29 +22,29 @@ import java.util.Map;
@Mixin(ModelOverride.Deserializer.class)
public class PatchOverrideDeserializer {
- @ModifyReturnValue(
- method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/ModelOverride;",
- at = @At(value = "RETURN"))
- private ModelOverride addCustomOverrides(ModelOverride original, @Local JsonObject jsonObject) {
- var originalData = (ModelOverrideData) original;
- originalData.setFirmamentOverrides(CustomModelOverrideParser.parseCustomModelOverrides(jsonObject));
- return original;
- }
+ @ModifyReturnValue(
+ method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/ModelOverride;",
+ at = @At(value = "RETURN"))
+ private ModelOverride addCustomOverrides(ModelOverride original, @Local JsonObject jsonObject) {
+ var originalData = (ModelOverrideData) (Object) original;
+ originalData.setFirmamentOverrides(CustomModelOverrideParser.parseCustomModelOverrides(jsonObject));
+ return original;
+ }
- @ModifyExpressionValue(
- method = "deserializeMinPropertyValues(Lcom/google/gson/JsonObject;)Ljava/util/List;",
- at = @At(value = "INVOKE", target = "Ljava/util/Map$Entry;getValue()Ljava/lang/Object;"))
- private Object removeFirmamentPredicatesFromJsonIteration(Object original, @Local Map.Entry<String, JsonElement> entry) {
- if (entry.getKey().startsWith("firmament:")) return new JsonPrimitive(0F);
- return original;
- }
+ @ModifyExpressionValue(
+ method = "deserializeMinPropertyValues(Lcom/google/gson/JsonObject;)Ljava/util/List;",
+ at = @At(value = "INVOKE", target = "Ljava/util/Map$Entry;getValue()Ljava/lang/Object;"))
+ private Object removeFirmamentPredicatesFromJsonIteration(Object original, @Local Map.Entry<String, JsonElement> entry) {
+ if (entry.getKey().startsWith("firmament:")) return new JsonPrimitive(0F);
+ return original;
+ }
- @Inject(
- method = "deserializeMinPropertyValues",
- at = @At(value = "INVOKE", target = "Ljava/util/Map;entrySet()Ljava/util/Set;")
- )
- private void whatever(JsonObject object, CallbackInfoReturnable<List<ModelOverride.Condition>> cir,
- @Local Map<Identifier, Float> maps) {
- maps.entrySet().removeIf(it -> it.getKey().getNamespace().equals("firmament"));
- }
+ @Inject(
+ method = "deserializeMinPropertyValues",
+ at = @At(value = "INVOKE", target = "Ljava/util/Map;entrySet()Ljava/util/Set;")
+ )
+ private void whatever(JsonObject object, CallbackInfoReturnable<List<ModelOverride.Condition>> cir,
+ @Local Map<Identifier, Float> maps) {
+ maps.entrySet().removeIf(it -> it.getKey().getNamespace().equals("firmament"));
+ }
}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ProvideBakerToJsonUnbakedModelPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ProvideBakerToJsonUnbakedModelPatch.java
new file mode 100644
index 0000000..c1ac119
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ProvideBakerToJsonUnbakedModelPatch.java
@@ -0,0 +1,27 @@
+package moe.nea.firmament.mixins.custommodels;
+
+import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
+import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
+import moe.nea.firmament.features.texturepack.JsonUnbakedModelFirmExtra;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.render.model.Baker;
+import net.minecraft.client.render.model.ModelBakeSettings;
+import net.minecraft.client.render.model.json.JsonUnbakedModel;
+import net.minecraft.client.texture.Sprite;
+import net.minecraft.client.util.SpriteIdentifier;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+import java.util.function.Function;
+
+/**
+ * @see JsonUnbakedModelDataHolder#storeExtraBaker_firmament
+ */
+@Mixin(targets = "net.minecraft.client.render.model.ModelBaker$BakerImpl")
+public abstract class ProvideBakerToJsonUnbakedModelPatch implements Baker {
+ @WrapOperation(method = "bake(Lnet/minecraft/client/render/model/UnbakedModel;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/JsonUnbakedModel;bake(Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;"))
+ private BakedModel provideExtraBakerToModel(JsonUnbakedModel instance, Function<SpriteIdentifier, Sprite> function, ModelBakeSettings modelBakeSettings, boolean bl, Operation<BakedModel> original) {
+ ((JsonUnbakedModelFirmExtra) instance).storeExtraBaker_firmament(this);
+ return original.call(instance, function, modelBakeSettings, bl);
+ }
+}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ReferenceCustomModelsPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ReferenceCustomModelsPatch.java
new file mode 100644
index 0000000..14c84ab
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ReferenceCustomModelsPatch.java
@@ -0,0 +1,37 @@
+package moe.nea.firmament.mixins.custommodels;
+
+import moe.nea.firmament.events.BakeExtraModelsEvent;
+import net.minecraft.client.render.model.BlockStatesLoader;
+import net.minecraft.client.render.model.ItemModel;
+import net.minecraft.client.render.model.ReferencedModelsCollector;
+import net.minecraft.client.render.model.UnbakedModel;
+import net.minecraft.client.util.ModelIdentifier;
+import net.minecraft.util.Identifier;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import java.util.Map;
+
+@Mixin(ReferencedModelsCollector.class)
+public abstract class ReferenceCustomModelsPatch {
+ @Shadow
+ protected abstract void addTopLevelModel(ModelIdentifier modelId, UnbakedModel model);
+
+ @Shadow
+ @Final
+ private Map<Identifier, UnbakedModel> inputs;
+
+ @Inject(method = "addBlockStates", at = @At("RETURN"))
+ private void addFirmamentReferencedModels(
+ BlockStatesLoader.BlockStateDefinition definition, CallbackInfo ci
+ ) {
+ inputs.keySet().stream().filter(it->it.toString().contains("firm")).forEach(System.out::println);
+ BakeExtraModelsEvent.Companion.publish(new BakeExtraModelsEvent(
+ (modelIdentifier, identifier) -> addTopLevelModel(modelIdentifier, new ItemModel(identifier))));
+
+ }
+}
diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java
index bc47d74..81ae3b8 100644
--- a/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java
@@ -17,33 +17,33 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(ModelOverrideList.class)
public class TestForFirmamentOverridePredicatesPatch {
- @ModifyArg(method = "<init>(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/List;)V",
- at = @At(
- value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z"
- ))
- public Object onInit(
- Object element,
- @Local ModelOverride modelOverride
- ) {
- var bakedOverride = (ModelOverrideList.BakedOverride) element;
- ((BakedOverrideData) bakedOverride)
- .setFirmamentOverrides(((ModelOverrideData) modelOverride).getFirmamentOverrides());
- return element;
- }
+ @ModifyArg(method = "<init>(Lnet/minecraft/client/render/model/Baker;Ljava/util/List;)V",
+ at = @At(
+ value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z"
+ ))
+ public Object onInit(
+ Object element,
+ @Local ModelOverride modelOverride
+ ) {
+ var bakedOverride = (ModelOverrideList.BakedOverride) element;
+ ((BakedOverrideData) (Object) bakedOverride)
+ .setFirmamentOverrides(((ModelOverrideData) (Object) modelOverride).getFirmamentOverrides());
+ return element;
+ }
- @ModifyExpressionValue(method = "apply", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;test([F)Z"))
- public boolean testFirmamentOverrides(boolean originalValue,
- @Local ModelOverrideList.BakedOverride bakedOverride,
- @Local(argsOnly = true) ItemStack stack) {
- if (!originalValue) return false;
- var overrideData = (BakedOverrideData) bakedOverride;
- var overrides = overrideData.getFirmamentOverrides();
- if (overrides == null) return true;
- if (!CustomSkyBlockTextures.TConfig.INSTANCE.getEnableModelOverrides()) return false;
- for (FirmamentModelPredicate firmamentOverride : overrides) {
- if (!firmamentOverride.test(stack))
- return false;
- }
- return true;
- }
+ @ModifyExpressionValue(method = "getModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;test([F)Z"))
+ public boolean testFirmamentOverrides(boolean originalValue,
+ @Local ModelOverrideList.BakedOverride bakedOverride,
+ @Local(argsOnly = true) ItemStack stack) {
+ if (!originalValue) return false;
+ var overrideData = (BakedOverrideData) (Object) bakedOverride;
+ var overrides = overrideData.getFirmamentOverrides();
+ if (overrides == null) return true;
+ if (!CustomSkyBlockTextures.TConfig.INSTANCE.getEnableModelOverrides()) return false;
+ for (FirmamentModelPredicate firmamentOverride : overrides) {
+ if (!firmamentOverride.test(stack))
+ return false;
+ }
+ return true;
+ }
}
diff --git a/src/main/kotlin/events/BakeExtraModelsEvent.kt b/src/main/kotlin/events/BakeExtraModelsEvent.kt
index f75bedc..adaa495 100644
--- a/src/main/kotlin/events/BakeExtraModelsEvent.kt
+++ b/src/main/kotlin/events/BakeExtraModelsEvent.kt
@@ -1,21 +1,24 @@
-
package moe.nea.firmament.events
-import java.util.function.Consumer
+import java.util.function.BiConsumer
+import net.minecraft.client.render.model.ReferencedModelsCollector
import net.minecraft.client.util.ModelIdentifier
+import net.minecraft.util.Identifier
+// TODO: Rename this event, since it is not really directly baking models anymore
class BakeExtraModelsEvent(
- private val addItemModel: Consumer<ModelIdentifier>,
- private val addAnyModel: Consumer<ModelIdentifier>,
+ private val addAnyModel: BiConsumer<ModelIdentifier, Identifier>,
) : FirmamentEvent() {
- fun addNonItemModel(modelIdentifier: ModelIdentifier) {
- this.addAnyModel.accept(modelIdentifier)
- }
+ fun addNonItemModel(modelIdentifier: ModelIdentifier, identifier: Identifier) {
+ this.addAnyModel.accept(modelIdentifier, identifier)
+ }
- fun addItemModel(modelIdentifier: ModelIdentifier) {
- this.addItemModel.accept(modelIdentifier)
- }
+ fun addItemModel(modelIdentifier: ModelIdentifier) {
+ addNonItemModel(
+ modelIdentifier,
+ modelIdentifier.id.withPrefixedPath(ReferencedModelsCollector.ITEM_DIRECTORY))
+ }
- companion object : FirmamentEventBus<BakeExtraModelsEvent>()
+ companion object : FirmamentEventBus<BakeExtraModelsEvent>()
}
diff --git a/src/main/kotlin/events/CustomItemModelEvent.kt b/src/main/kotlin/events/CustomItemModelEvent.kt
index e50eca4..4328d77 100644
--- a/src/main/kotlin/events/CustomItemModelEvent.kt
+++ b/src/main/kotlin/events/CustomItemModelEvent.kt
@@ -2,35 +2,37 @@ package moe.nea.firmament.events
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
+import net.minecraft.client.render.item.ItemModels
import net.minecraft.client.render.model.BakedModel
-import net.minecraft.client.render.model.BakedModelManager
import net.minecraft.client.util.ModelIdentifier
import net.minecraft.item.ItemStack
+import moe.nea.firmament.util.ErrorUtil
import moe.nea.firmament.util.collections.WeakCache
data class CustomItemModelEvent(
- val itemStack: ItemStack,
- var overrideModel: ModelIdentifier? = null,
+ val itemStack: ItemStack,
+ var overrideModel: ModelIdentifier? = null,
) : FirmamentEvent() {
- companion object : FirmamentEventBus<CustomItemModelEvent>() {
- val cache =
- WeakCache.memoize<ItemStack, BakedModelManager, Optional<BakedModel>>("CustomItemModels") { stack, models ->
- val modelId = getModelIdentifier(stack) ?: return@memoize Optional.empty()
- val bakedModel = models.getModel(modelId)
- if (bakedModel === models.missingModel) return@memoize Optional.empty()
- Optional.of(bakedModel)
- }
+ companion object : FirmamentEventBus<CustomItemModelEvent>() {
+ val cache =
+ WeakCache.memoize<ItemStack, ItemModels, Optional<BakedModel>>("CustomItemModels") { stack, models ->
+ val modelId = getModelIdentifier(stack) ?: return@memoize Optional.empty()
+ ErrorUtil.softCheck("Model Id needs to have an inventory variant", modelId.variant() == "inventory")
+ val bakedModel = models.getModel(modelId.id)
+ if (bakedModel == null || bakedModel === models.missingModelSupplier.get()) return@memoize Optional.empty()
+ Optional.of(bakedModel)
+ }
- @JvmStatic
- fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? {
- if (itemStack == null) return null
- return publish(CustomItemModelEvent(itemStack)).overrideModel
- }
+ @JvmStatic
+ fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? {
+ if (itemStack == null) return null
+ return publish(CustomItemModelEvent(itemStack)).overrideModel
+ }
- @JvmStatic
- fun getModel(itemStack: ItemStack?, thing: BakedModelManager): BakedModel? {
- if (itemStack == null) return null
- return cache.invoke(itemStack, thing).getOrNull()
- }
- }
+ @JvmStatic
+ fun getModel(itemStack: ItemStack?, thing: ItemModels): BakedModel? {
+ if (itemStack == null) return null
+ return cache.invoke(itemStack, thing).getOrNull()
+ }
+ }
}
diff --git a/src/main/kotlin/events/DebugInstantiateEvent.kt b/src/main/kotlin/events/DebugInstantiateEvent.kt
new file mode 100644
index 0000000..3470a8c
--- /dev/null
+++ b/src/main/kotlin/events/DebugInstantiateEvent.kt
@@ -0,0 +1,9 @@
+package moe.nea.firmament.events
+
+/**
+ * Called in a devenv after minecraft has been initialized. This event should be used to force instantiation of lazy
+ * variables (and similar late init) to cause any possible issues to materialize.
+ */
+class DebugInstantiateEvent : FirmamentEvent() {
+ companion object : FirmamentEventBus<DebugInstantiateEvent>()
+}
diff --git a/src/main/kotlin/events/FinalizeResourceManagerEvent.kt b/src/main/kotlin/events/FinalizeResourceManagerEvent.kt
index 0d411f1..12167f8 100644
--- a/src/main/kotlin/events/FinalizeResourceManagerEvent.kt
+++ b/src/main/kotlin/events/FinalizeResourceManagerEvent.kt
@@ -5,31 +5,28 @@ import java.util.concurrent.Executor
import net.minecraft.resource.ReloadableResourceManagerImpl
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceReloader
-import net.minecraft.util.profiler.Profiler
data class FinalizeResourceManagerEvent(
- val resourceManager: ReloadableResourceManagerImpl,
+ val resourceManager: ReloadableResourceManagerImpl,
) : FirmamentEvent() {
- companion object : FirmamentEventBus<FinalizeResourceManagerEvent>()
+ companion object : FirmamentEventBus<FinalizeResourceManagerEvent>()
- inline fun registerOnApply(name: String, crossinline function: () -> Unit) {
- resourceManager.registerReloader(object : ResourceReloader {
- override fun reload(
- synchronizer: ResourceReloader.Synchronizer,
- manager: ResourceManager?,
- prepareProfiler: Profiler?,
- applyProfiler: Profiler?,
- prepareExecutor: Executor?,
- applyExecutor: Executor
- ): CompletableFuture<Void> {
- return CompletableFuture.completedFuture(Unit)
- .thenCompose(synchronizer::whenPrepared)
- .thenAcceptAsync({ function() }, applyExecutor)
- }
+ inline fun registerOnApply(name: String, crossinline function: () -> Unit) {
+ resourceManager.registerReloader(object : ResourceReloader {
+ override fun reload(
+ synchronizer: ResourceReloader.Synchronizer,
+ manager: ResourceManager,
+ prepareExecutor: Executor,
+ applyExecutor: Executor
+ ): CompletableFuture<Void> {
+ return CompletableFuture.completedFuture(Unit)
+ .thenCompose(synchronizer::whenPrepared)
+ .thenAcceptAsync({ function() }, applyExecutor)
+ }
- override fun getName(): String {
- return name
- }
- })
- }
+ override fun getName(): String {
+ return name
+ }
+ })
+ }
}
diff --git a/src/main/kotlin/events/IsSlotProtectedEvent.kt b/src/main/kotlin/events/IsSlotProtectedEvent.kt
index cd431f7..cd2b676 100644
--- a/src/main/kotlin/events/IsSlotProtectedEvent.kt
+++ b/src/main/kotlin/events/IsSlotProtectedEvent.kt
@@ -37,7 +37,7 @@ data class IsSlotProtectedEvent(
val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride)
publish(event)
if (event.isProtected && !event.silent) {
- MC.player?.sendMessage(Text.translatable("firmament.protectitem").append(event.itemStack.name))
+ MC.sendChat(Text.translatable("firmament.protectitem").append(event.itemStack.name))
CommonSoundEffects.playFailure()
}
return event.isProtected
diff --git a/src/main/kotlin/events/RegisterCustomShadersEvent.kt b/src/main/kotlin/events/RegisterCustomShadersEvent.kt
deleted file mode 100644
index 2f6d1f8..0000000
--- a/src/main/kotlin/events/RegisterCustomShadersEvent.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package moe.nea.firmament.events
-
-import com.mojang.datafixers.util.Pair
-import java.util.function.Consumer
-import net.minecraft.client.gl.ShaderProgram
-import net.minecraft.client.render.VertexFormat
-import net.minecraft.resource.ResourceFactory
-import moe.nea.firmament.Firmament
-
-data class RegisterCustomShadersEvent(
- val list: MutableList<Pair<ShaderProgram, Consumer<ShaderProgram>>>,
- val resourceFactory: ResourceFactory,
-) : FirmamentEvent() {
- companion object : FirmamentEventBus<RegisterCustomShadersEvent>()
-
- fun register(name: String, vertexFormat: VertexFormat, saver: Consumer<ShaderProgram>) {
- require(name.startsWith("firmament_"))
- try {
- list.add(Pair.of(ShaderProgram(resourceFactory, name, vertexFormat), saver))
- } catch (ex: Exception) {
- Firmament.logger.fatal("Could not load firmament shader $name", ex)
- }
- }
-}
diff --git a/src/main/kotlin/events/SlotRenderEvents.kt b/src/main/kotlin/events/SlotRenderEvents.kt
index 5431573..5234176 100644
--- a/src/main/kotlin/events/SlotRenderEvents.kt
+++ b/src/main/kotlin/events/SlotRenderEvents.kt
@@ -3,20 +3,19 @@
package moe.nea.firmament.events
import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.render.RenderLayer
import net.minecraft.client.texture.Sprite
import net.minecraft.screen.slot.Slot
import net.minecraft.util.Identifier
import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.render.drawGuiTexture
interface SlotRenderEvents {
val context: DrawContext
val slot: Slot
- val mouseX: Int
- val mouseY: Int
- val delta: Float
- fun highlight(sprite: Sprite) {
- context.drawSprite(
+ fun highlight(sprite: Identifier) {
+ context.drawGuiTexture(
slot.x, slot.y, 0, 16, 16,
sprite
)
@@ -24,9 +23,6 @@ interface SlotRenderEvents {
data class Before(
override val context: DrawContext, override val slot: Slot,
- override val mouseX: Int,
- override val mouseY: Int,
- override val delta: Float
) : FirmamentEvent(),
SlotRenderEvents {
companion object : FirmamentEventBus<Before>()
@@ -34,9 +30,6 @@ interface SlotRenderEvents {
data class After(
override val context: DrawContext, override val slot: Slot,
- override val mouseX: Int,
- override val mouseY: Int,
- override val delta: Float
) : FirmamentEvent(),
SlotRenderEvents {
companion object : FirmamentEventBus<After>()
diff --git a/src/main/kotlin/events/WorldReadyEvent.kt b/src/main/kotlin/events/WorldReadyEvent.kt
index 2c76c44..c79b100 100644
--- a/src/main/kotlin/events/WorldReadyEvent.kt
+++ b/src/main/kotlin/events/WorldReadyEvent.kt
@@ -1,7 +1,10 @@
-
-
package moe.nea.firmament.events
class WorldReadyEvent : FirmamentEvent() {
- companion object : FirmamentEventBus<WorldReadyEvent>()
+ companion object : FirmamentEventBus<WorldReadyEvent>()
+// class FullyLoaded : FirmamentEvent() {
+// companion object : FirmamentEventBus<FullyLoaded>() {
+// TODO: check WorldLoadingState
+// }
+// }
}
diff --git a/src/main/kotlin/events/WorldRenderLastEvent.kt b/src/main/kotlin/events/WorldRenderLastEvent.kt
index 21a670d..3c2103d 100644
--- a/src/main/kotlin/events/WorldRenderLastEvent.kt
+++ b/src/main/kotlin/events/WorldRenderLastEvent.kt
@@ -17,10 +17,7 @@ import net.minecraft.util.math.Vec3d
data class WorldRenderLastEvent(
val matrices: MatrixStack,
val tickCounter: RenderTickCounter,
- val renderBlockOutline: Boolean,
val camera: Camera,
- val gameRenderer: GameRenderer,
- val lightmapTextureManager: LightmapTextureManager,
val vertexConsumers: VertexConsumerProvider.Immediate,
) : FirmamentEvent() {
companion object : FirmamentEventBus<WorldRenderLastEvent>()
diff --git a/src/main/kotlin/features/chat/ChatLinks.kt b/src/main/kotlin/features/chat/ChatLinks.kt
index 0681f57..5bce3f4 100644
--- a/src/main/kotlin/features/chat/ChatLinks.kt
+++ b/src/main/kotlin/features/chat/ChatLinks.kt
@@ -13,8 +13,10 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
import kotlin.math.min
import net.minecraft.client.gui.screen.ChatScreen
+import net.minecraft.client.render.RenderLayer
import net.minecraft.client.texture.NativeImage
import net.minecraft.client.texture.NativeImageBackedTexture
+import net.minecraft.scoreboard.ScoreboardCriterion.RenderType
import net.minecraft.text.ClickEvent
import net.minecraft.text.HoverEvent
import net.minecraft.text.Style
@@ -28,6 +30,7 @@ import moe.nea.firmament.events.ScreenRenderPostEvent
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.render.drawTexture
import moe.nea.firmament.util.transformEachRecursively
import moe.nea.firmament.util.unformattedString
diff --git a/src/main/kotlin/features/debug/DeveloperFeatures.kt b/src/main/kotlin/features/debug/DeveloperFeatures.kt
index 2001a3f..d4b118b 100644
--- a/src/main/kotlin/features/debug/DeveloperFeatures.kt
+++ b/src/main/kotlin/features/debug/DeveloperFeatures.kt
@@ -37,10 +37,10 @@ object DeveloperFeatures : FirmamentFeature {
builder.directory(gradleDir.toFile())
builder.inheritIO()
val process = builder.start()
- MC.player?.sendMessage(Text.translatable("firmament.dev.resourcerebuild.start"))
+ MC.sendChat(Text.translatable("firmament.dev.resourcerebuild.start"))
val startTime = TimeMark.now()
process.toHandle().onExit().thenApply {
- MC.player?.sendMessage(Text.stringifiedTranslatable(
+ MC.sendChat(Text.stringifiedTranslatable(
"firmament.dev.resourcerebuild.done",
startTime.passedTime()))
Unit
diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt
index 83e3aff..13320dc 100644
--- a/src/main/kotlin/features/debug/PowerUserTools.kt
+++ b/src/main/kotlin/features/debug/PowerUserTools.kt
@@ -9,6 +9,7 @@ import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
+import net.minecraft.nbt.NbtOps
import net.minecraft.text.Text
import net.minecraft.text.TextCodecs
import net.minecraft.util.hit.BlockHitResult
@@ -54,15 +55,13 @@ object PowerUserTools : FirmamentFeature {
var lastCopiedStack: Pair<ItemStack, Text>? = null
set(value) {
field = value
- if (value != null)
- lastCopiedStackViewTime = true
+ if (value != null) lastCopiedStackViewTime = true
}
var lastCopiedStackViewTime = false
@Subscribe
fun resetLastCopiedStack(event: TickEvent) {
- if (!lastCopiedStackViewTime)
- lastCopiedStack = null
+ if (!lastCopiedStackViewTime) lastCopiedStack = null
lastCopiedStackViewTime = false
}
@@ -154,13 +153,13 @@ object PowerUserTools : FirmamentFeature {
}
ClipboardUtils.setTextContent(skullTexture.toString())
lastCopiedStack =
- Pair(
- item,
- Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString())
- )
+ Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString()))
println("Copied skull id: $skullTexture")
} else if (it.matches(TConfig.copyItemStack)) {
- ClipboardUtils.setTextContent(item.encode(MC.currentOrDefaultRegistries).toPrettyString())
+ ClipboardUtils.setTextContent(
+ ItemStack.CODEC
+ .encodeStart(MC.currentOrDefaultRegistries.getOps(NbtOps.INSTANCE), item)
+ .orThrow.toPrettyString())
lastCopiedStack = Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.stack"))
}
}
diff --git a/src/main/kotlin/features/diana/AncestralSpadeSolver.kt b/src/main/kotlin/features/diana/AncestralSpadeSolver.kt
index ef3ead1..8918e66 100644
--- a/src/main/kotlin/features/diana/AncestralSpadeSolver.kt
+++ b/src/main/kotlin/features/diana/AncestralSpadeSolver.kt
@@ -104,12 +104,13 @@ object AncestralSpadeSolver : SubscriptionOwner {
if (!isEnabled()) return
RenderInWorldContext.renderInWorld(event) {
nextGuess?.let {
- color(1f, 1f, 0f, 0.5f)
- tinyBlock(it, 1f)
+ tinyBlock(it, 1f, 0x80FFFFFF.toInt())
+ // TODO: replace this
color(1f, 1f, 0f, 1f)
tracer(it, lineWidth = 3f)
}
if (particlePositions.size > 2 && lastDing.passedTime() < 10.seconds && nextGuess != null) {
+ // TODO: replace this // TODO: add toggle
color(0f, 1f, 0f, 0.7f)
line(particlePositions)
}
diff --git a/src/main/kotlin/features/diana/NearbyBurrowsSolver.kt b/src/main/kotlin/features/diana/NearbyBurrowsSolver.kt
index ab1518a..2fb4002 100644
--- a/src/main/kotlin/features/diana/NearbyBurrowsSolver.kt
+++ b/src/main/kotlin/features/diana/NearbyBurrowsSolver.kt
@@ -1,6 +1,6 @@
-
package moe.nea.firmament.features.diana
+import me.shedaniel.math.Color
import kotlin.time.Duration.Companion.seconds
import net.minecraft.particle.ParticleTypes
import net.minecraft.util.math.BlockPos
@@ -20,125 +20,125 @@ import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorl
object NearbyBurrowsSolver : SubscriptionOwner {
- private val recentlyDugBurrows: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(20)
- private val recentEnchantParticles: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(500)
- private var lastBlockClick: BlockPos? = null
-
- enum class BurrowType {
- START, MOB, TREASURE
- }
-
- val burrows = mutableMapOf<BlockPos, BurrowType>()
-
- @Subscribe
- fun onChatEvent(event: ProcessChatEvent) {
- val lastClickedBurrow = lastBlockClick ?: return
- if (event.unformattedString.startsWith("You dug out a Griffin Burrow!") ||
- event.unformattedString.startsWith(" ☠ You were killed by") ||
- event.unformattedString.startsWith("You finished the Griffin burrow chain!")
- ) {
- markAsDug(lastClickedBurrow)
- burrows.remove(lastClickedBurrow)
- }
- }
-
-
- fun wasRecentlyDug(blockPos: BlockPos): Boolean {
- val lastDigTime = recentlyDugBurrows[blockPos] ?: TimeMark.farPast()
- return lastDigTime.passedTime() < 10.seconds
- }
-
- fun markAsDug(blockPos: BlockPos) {
- recentlyDugBurrows[blockPos] = TimeMark.now()
- }
-
- fun wasRecentlyEnchanted(blockPos: BlockPos): Boolean {
- val lastEnchantTime = recentEnchantParticles[blockPos] ?: TimeMark.farPast()
- return lastEnchantTime.passedTime() < 4.seconds
- }
-
- fun markAsEnchanted(blockPos: BlockPos) {
- recentEnchantParticles[blockPos] = TimeMark.now()
- }
-
- @Subscribe
- fun onParticles(event: ParticleSpawnEvent) {
- if (!DianaWaypoints.TConfig.nearbyWaypoints) return
-
- val position: BlockPos = event.position.toBlockPos().down()
-
- if (wasRecentlyDug(position)) return
-
- val isEven50Spread = (event.offset.x == 0.5f && event.offset.z == 0.5f)
-
- if (event.particleEffect.type == ParticleTypes.ENCHANT) {
- if (event.count == 5 && event.speed == 0.05F && event.offset.y == 0.4F && isEven50Spread) {
- markAsEnchanted(position)
- }
- return
- }
-
- if (!wasRecentlyEnchanted(position)) return
-
- if (event.particleEffect.type == ParticleTypes.ENCHANTED_HIT
- && event.count == 4
- && event.speed == 0.01F
- && event.offset.y == 0.1f
- && isEven50Spread
- ) {
- burrows[position] = BurrowType.START
- }
- if (event.particleEffect.type == ParticleTypes.CRIT
- && event.count == 3
- && event.speed == 0.01F
- && event.offset.y == 0.1F
- && isEven50Spread
- ) {
- burrows[position] = BurrowType.MOB
- }
- if (event.particleEffect.type == ParticleTypes.DRIPPING_LAVA
- && event.count == 2
- && event.speed == 0.01F
- && event.offset.y == 0.1F
- && event.offset.x == 0.35F && event.offset.z == 0.35f
- ) {
- burrows[position] = BurrowType.TREASURE
- }
- }
-
- @Subscribe
- fun onRender(event: WorldRenderLastEvent) {
- if (!DianaWaypoints.TConfig.nearbyWaypoints) return
- renderInWorld(event) {
- for ((location, burrow) in burrows) {
- when (burrow) {
- BurrowType.START -> color(.2f, .8f, .2f, 0.4f)
- BurrowType.MOB -> color(0.3f, 0.4f, 0.9f, 0.4f)
- BurrowType.TREASURE -> color(1f, 0.7f, 0.2f, 0.4f)
- }
- block(location)
- }
- }
- }
-
- @Subscribe
- fun onSwapWorld(worldReadyEvent: WorldReadyEvent) {
- burrows.clear()
- recentEnchantParticles.clear()
- recentlyDugBurrows.clear()
- lastBlockClick = null
- }
-
- fun onBlockClick(blockPos: BlockPos) {
- if (!DianaWaypoints.TConfig.nearbyWaypoints) return
- burrows.remove(blockPos)
- lastBlockClick = blockPos
- }
-
- override val delegateFeature: FirmamentFeature
- get() = DianaWaypoints
+ private val recentlyDugBurrows: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(20)
+ private val recentEnchantParticles: MutableMap<BlockPos, TimeMark> = mutableMapWithMaxSize(500)
+ private var lastBlockClick: BlockPos? = null
+
+ enum class BurrowType {
+ START, MOB, TREASURE
+ }
+
+ val burrows = mutableMapOf<BlockPos, BurrowType>()
+
+ @Subscribe
+ fun onChatEvent(event: ProcessChatEvent) {
+ val lastClickedBurrow = lastBlockClick ?: return
+ if (event.unformattedString.startsWith("You dug out a Griffin Burrow!") ||
+ event.unformattedString.startsWith(" ☠ You were killed by") ||
+ event.unformattedString.startsWith("You finished the Griffin burrow chain!")
+ ) {
+ markAsDug(lastClickedBurrow)
+ burrows.remove(lastClickedBurrow)
+ }
+ }
+
+
+ fun wasRecentlyDug(blockPos: BlockPos): Boolean {
+ val lastDigTime = recentlyDugBurrows[blockPos] ?: TimeMark.farPast()
+ return lastDigTime.passedTime() < 10.seconds
+ }
+
+ fun markAsDug(blockPos: BlockPos) {
+ recentlyDugBurrows[blockPos] = TimeMark.now()
+ }
+
+ fun wasRecentlyEnchanted(blockPos: BlockPos): Boolean {
+ val lastEnchantTime = recentEnchantParticles[blockPos] ?: TimeMark.farPast()
+ return lastEnchantTime.passedTime() < 4.seconds
+ }
+
+ fun markAsEnchanted(blockPos: BlockPos) {
+ recentEnchantParticles[blockPos] = TimeMark.now()
+ }
+
+ @Subscribe
+ fun onParticles(event: ParticleSpawnEvent) {
+ if (!DianaWaypoints.TConfig.nearbyWaypoints) return
+
+ val position: BlockPos = event.position.toBlockPos().down()
+
+ if (wasRecentlyDug(position)) return
+
+ val isEven50Spread = (event.offset.x == 0.5f && event.offset.z == 0.5f)
+
+ if (event.particleEffect.type == ParticleTypes.ENCHANT) {
+ if (event.count == 5 && event.speed == 0.05F && event.offset.y == 0.4F && isEven50Spread) {
+ markAsEnchanted(position)
+ }
+ return
+ }
+
+ if (!wasRecentlyEnchanted(position)) return
+
+ if (event.particleEffect.type == ParticleTypes.ENCHANTED_HIT
+ && event.count == 4
+ && event.speed == 0.01F
+ && event.offset.y == 0.1f
+ && isEven50Spread
+ ) {
+ burrows[position] = BurrowType.START
+ }
+ if (event.particleEffect.type == ParticleTypes.CRIT
+ && event.count == 3
+ && event.speed == 0.01F
+ && event.offset.y == 0.1F
+ && isEven50Spread
+ ) {
+ burrows[position] = BurrowType.MOB
+ }
+ if (event.particleEffect.type == ParticleTypes.DRIPPING_LAVA
+ && event.count == 2
+ && event.speed == 0.01F
+ && event.offset.y == 0.1F
+ && event.offset.x == 0.35F && event.offset.z == 0.35f
+ ) {
+ burrows[position] = BurrowType.TREASURE
+ }
+ }
+
+ @Subscribe
+ fun onRender(event: WorldRenderLastEvent) {
+ if (!DianaWaypoints.TConfig.nearbyWaypoints) return
+ renderInWorld(event) {
+ for ((location, burrow) in burrows) {
+ val color = when (burrow) {
+ BurrowType.START -> Color.ofRGBA(.2f, .8f, .2f, 0.4f)
+ BurrowType.MOB -> Color.ofRGBA(0.3f, 0.4f, 0.9f, 0.4f)
+ BurrowType.TREASURE -> Color.ofRGBA(1f, 0.7f, 0.2f, 0.4f)
+ }
+ block(location, color.color)
+ }
+ }
+ }
+
+ @Subscribe
+ fun onSwapWorld(worldReadyEvent: WorldReadyEvent) {
+ burrows.clear()
+ recentEnchantParticles.clear()
+ recentlyDugBurrows.clear()
+ lastBlockClick = null
+ }
+
+ fun onBlockClick(blockPos: BlockPos) {
+ if (!DianaWaypoints.TConfig.nearbyWaypoints) return
+ burrows.remove(blockPos)
+ lastBlockClick = blockPos
+ }
+
+ override val delegateFeature: FirmamentFeature
+ get() = DianaWaypoints
}
fun Position.toBlockPos(): BlockPos {
- return BlockPos(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z))
+ return BlockPos(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z))
}
diff --git a/src/main/kotlin/features/inventory/CraftingOverlay.kt b/src/main/kotlin/features/inventory/CraftingOverlay.kt
index a958e25..d2c79fd 100644
--- a/src/main/kotlin/features/inventory/CraftingOverlay.kt
+++ b/src/main/kotlin/features/inventory/CraftingOverlay.kt
@@ -69,7 +69,7 @@ object CraftingOverlay : FirmamentFeature {
if (!slot.hasStack()) {
val itemStack = SBItemStack(expectedItem)?.asImmutableItemStack() ?: return
event.context.drawItem(itemStack, event.slot.x, event.slot.y)
- event.context.drawItemInSlot(
+ event.context.drawStackOverlay(
MC.font,
itemStack,
event.slot.x,
diff --git a/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt b/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt
index 77f5071..26712da 100644
--- a/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt
+++ b/src/main/kotlin/features/inventory/ItemRarityCosmetics.kt
@@ -4,6 +4,7 @@ package moe.nea.firmament.features.inventory
import java.awt.Color
import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.render.RenderLayer
import net.minecraft.item.ItemStack
import net.minecraft.util.Formatting
import net.minecraft.util.Identifier
@@ -16,6 +17,7 @@ import moe.nea.firmament.util.MC
import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.collections.lastNotNullOfOrNull
import moe.nea.firmament.util.collections.memoizeIdentity
+import moe.nea.firmament.util.render.drawGuiTexture
import moe.nea.firmament.util.unformattedString
object ItemRarityCosmetics : FirmamentFeature {
@@ -43,10 +45,10 @@ object ItemRarityCosmetics : FirmamentFeature {
"SUPREME" to Formatting.DARK_RED,
).mapValues {
val c = Color(it.value.colorValue!!)
- Triple(c.red / 255F, c.green / 255F, c.blue / 255F)
+ c.rgb
}
- private fun getSkyblockRarity0(itemStack: ItemStack): Triple<Float, Float, Float>? {
+ private fun getSkyblockRarity0(itemStack: ItemStack): Int? {
return itemStack.loreAccordingToNbt.lastNotNullOfOrNull {
val entry = it.unformattedString
rarityToColor.entries.find { (k, v) -> k in entry }?.value
@@ -57,13 +59,13 @@ object ItemRarityCosmetics : FirmamentFeature {
fun drawItemStackRarity(drawContext: DrawContext, x: Int, y: Int, item: ItemStack) {
- val (r, g, b) = getSkyblockRarity(item) ?: return
- drawContext.drawSprite(
+ val rgb = getSkyblockRarity(item) ?: return
+ drawContext.drawGuiTexture(
+ RenderLayer::getGuiTextured,
+ Identifier.of("firmament:item_rarity_background"),
x, y,
- 0,
16, 16,
- MC.guiAtlasManager.getSprite(Identifier.of("firmament:item_rarity_background")),
- r, g, b, 1F
+ rgb
)
}
diff --git a/src/main/kotlin/features/inventory/PetFeatures.kt b/src/main/kotlin/features/inventory/PetFeatures.kt
index 2c11e76..5ca10f7 100644
--- a/src/main/kotlin/features/inventory/PetFeatures.kt
+++ b/src/main/kotlin/features/inventory/PetFeatures.kt
@@ -7,6 +7,7 @@ import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.petData
+import moe.nea.firmament.util.render.drawGuiTexture
import moe.nea.firmament.util.useMatch
object PetFeatures : FirmamentFeature {
@@ -28,9 +29,9 @@ object PetFeatures : FirmamentFeature {
val stack = event.slot.stack
if (stack.petData?.active == true)
petMenuTitle.useMatch(MC.screenName ?: return) {
- event.context.drawSprite(
+ event.context.drawGuiTexture(
event.slot.x, event.slot.y, 0, 16, 16,
- MC.guiAtlasManager.getSprite(Identifier.of("firmament:selected_pet_background"))
+ Identifier.of("firmament:selected_pet_background")
)
}
}
diff --git a/src/main/kotlin/features/inventory/SlotLocking.kt b/src/main/kotlin/features/inventory/SlotLocking.kt
index de54005..fc09476 100644
--- a/src/main/kotlin/features/inventory/SlotLocking.kt
+++ b/src/main/kotlin/features/inventory/SlotLocking.kt
@@ -35,6 +35,7 @@ import moe.nea.firmament.util.mc.ScreenUtil.getSlotByIndex
import moe.nea.firmament.util.mc.SlotUtils.swapWithHotBar
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt
+import moe.nea.firmament.util.render.GuiRenderLayers
import moe.nea.firmament.util.render.drawLine
import moe.nea.firmament.util.skyblockUUID
import moe.nea.firmament.util.unformattedString
@@ -211,6 +212,11 @@ object SlotLocking : FirmamentFeature {
}
if (it.matches(TConfig.slotBind)) {
storedLockingSlot = null
+ val boundSlots = DConfig.data?.boundSlots ?: return
+ if (slot != null)
+ boundSlots.entries.removeIf {
+ it.value == slot.index || it.key == slot.index
+ }
}
}
@@ -331,24 +337,22 @@ object SlotLocking : FirmamentFeature {
val isSlotLocked = it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())
val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf())
if (isSlotLocked || isUUIDLocked) {
- RenderSystem.disableDepthTest()
- it.context.drawSprite(
- it.slot.x, it.slot.y, 0,
+ it.context.drawGuiTexture(
+ GuiRenderLayers.GUI_TEXTURED_NO_DEPTH,
+ when {
+ isSlotLocked ->
+ (Identifier.of("firmament:slot_locked"))
+
+ isUUIDLocked ->
+ (Identifier.of("firmament:uuid_locked"))
+
+ else ->
+ error("unreachable")
+ },
+ it.slot.x, it.slot.y,
16, 16,
- MC.guiAtlasManager.getSprite(
- when {
- isSlotLocked ->
- (Identifier.of("firmament:slot_locked"))
-
- isUUIDLocked ->
- (Identifier.of("firmament:uuid_locked"))
-
- else ->
- error("unreachable")
- }
- )
+ -1
)
- RenderSystem.enableDepthTest()
}
}
}
diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButton.kt b/src/main/kotlin/features/inventory/buttons/InventoryButton.kt
index be173bd..a46bd76 100644
--- a/src/main/kotlin/features/inventory/buttons/InventoryButton.kt
+++ b/src/main/kotlin/features/inventory/buttons/InventoryButton.kt
@@ -18,6 +18,7 @@ import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.collections.memoize
+import moe.nea.firmament.util.render.drawGuiTexture
@Serializable
data class InventoryButton(
@@ -54,13 +55,13 @@ data class InventoryButton(
}
fun render(context: DrawContext) {
- context.drawSprite(
+ context.drawGuiTexture(
0,
0,
0,
dimensions.width,
dimensions.height,
- MC.guiAtlasManager.getSprite(Identifier.of("firmament:inventory_button_background"))
+ Identifier.of("firmament:inventory_button_background")
)
context.drawItem(getItem(), 1, 1)
}
diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt b/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt
index c57563e..7bf9c73 100644
--- a/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt
+++ b/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt
@@ -84,7 +84,6 @@ class InventoryButtonEditor(
context.matrices.push()
context.matrices.translate(0f, 0f, -10f)
context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1)
- context.setShaderColor(1f, 1f, 1f, 1f)
context.matrices.pop()
for (button in buttons) {
val buttonPosition = button.getBounds(lastGuiRect)
diff --git a/src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt b/src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt
index 5c1ac34..8fad4df 100644
--- a/src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt
+++ b/src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt
@@ -40,6 +40,7 @@ sealed interface StorageBackingHandle {
* representable as a [StorageBackingHandle], meaning another screen is open, for example the enderchest icon
* selection screen.
*/
+ @OptIn(ExperimentalContracts::class)
fun fromScreen(screen: Screen?): StorageBackingHandle? {
contract {
returnsNotNull() implies (screen != null)
diff --git a/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt b/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt
index f81315d..a5b2fd6 100644
--- a/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt
+++ b/src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt
@@ -21,6 +21,7 @@ import moe.nea.firmament.util.MoulConfigUtils.clickMCComponentInPlace
import moe.nea.firmament.util.MoulConfigUtils.drawMCComponentInPlace
import moe.nea.firmament.util.assertTrueOr
import moe.nea.firmament.util.customgui.customGui
+import moe.nea.firmament.util.render.drawGuiTexture
class StorageOverlayScreen : Screen(Text.literal("")) {
@@ -162,13 +163,11 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
context.drawGuiTexture(upperBackgroundSprite,
measurements.x,
measurements.y,
- 0,
measurements.overviewWidth,
measurements.overviewHeight)
context.drawGuiTexture(playerInventorySprite,
measurements.playerX,
measurements.playerY,
- 0,
PLAYER_WIDTH,
PLAYER_HEIGHT)
}
@@ -188,7 +187,7 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
items.withIndex().forEach { (index, item) ->
val (x, y) = getPlayerInventorySlotPosition(index)
context.drawItem(item, x, y, 0)
- context.drawItemInSlot(textRenderer, item, x, y)
+ context.drawStackOverlay(textRenderer, item, x, y)
}
}
@@ -357,7 +356,7 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
val slotY = (index / 9) * SLOT_SIZE + y + 4 + textRenderer.fontHeight + 1
if (slots == null) {
context.drawItem(stack, slotX, slotY)
- context.drawItemInSlot(textRenderer, stack, slotX, slotY)
+ context.drawStackOverlay(textRenderer, stack, slotX, slotY)
} else {
val slot = slots[index]
slot.x = slotX - slotOffset.x
diff --git a/src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt b/src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt
index 2cbd54e..9112fab 100644
--- a/src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt
+++ b/src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt
@@ -111,7 +111,7 @@ class StorageOverviewScreen() : Screen(Text.empty()) {
context.fill(x, y, x + 18, y + 18, 0x40808080.toInt())
}
context.drawItem(stack, x + 1, y + 1)
- context.drawItemInSlot(MC.font, stack, x + 1, y + 1)
+ context.drawStackOverlay(MC.font, stack, x + 1, y + 1)
}
}
diff --git a/src/main/kotlin/features/mining/CommissionFeatures.kt b/src/main/kotlin/features/mining/CommissionFeatures.kt
index d0acdfd..faba253 100644
--- a/src/main/kotlin/features/mining/CommissionFeatures.kt
+++ b/src/main/kotlin/features/mining/CommissionFeatures.kt
@@ -1,6 +1,6 @@
package moe.nea.firmament.features.mining
-import net.minecraft.util.Identifier
+import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.gui.config.ManagedConfig
@@ -19,10 +19,8 @@ object CommissionFeatures {
if (!Config.highlightCompletedCommissions) return
if (MC.screenName != "Commissions") return
val stack = event.slot.stack
- if(stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) {
- event.highlight(
- MC.guiAtlasManager.getSprite(Identifier.of("firmament:completed_commission_background"))
- )
+ if (stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) {
+ event.highlight(Firmament.identifier("completed_commission_background"))
}
}
}
diff --git a/src/main/kotlin/features/mining/HotmPresets.kt b/src/main/kotlin/features/mining/HotmPresets.kt
index 3f83f3d..533aa1e 100644
--- a/src/main/kotlin/features/mining/HotmPresets.kt
+++ b/src/main/kotlin/features/mining/HotmPresets.kt
@@ -9,9 +9,7 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.Items
import net.minecraft.screen.GenericContainerScreenHandler
-import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.slot.Slot
-import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
@@ -31,6 +29,7 @@ import moe.nea.firmament.util.customgui.customGui
import moe.nea.firmament.util.mc.CommonTextures
import moe.nea.firmament.util.mc.SlotUtils.clickRightMouseButton
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
+import moe.nea.firmament.util.render.drawGuiTexture
import moe.nea.firmament.util.unformattedString
import moe.nea.firmament.util.useMatch
@@ -81,7 +80,7 @@ object HotmPresets {
override fun render(drawContext: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
drawContext.drawGuiTexture(
CommonTextures.genericWidget(),
- bounds.x, bounds.y, 0,
+ bounds.x, bounds.y,
bounds.width,
bounds.height,
)
@@ -191,7 +190,7 @@ object HotmPresets {
if (hotmInventoryName == MC.screenName
&& event.slot.stack.displayNameAccordingToNbt.unformattedString in highlightedPerks
) {
- event.highlight(MC.guiAtlasManager.getSprite(Firmament.identifier("hotm_perk_preset")))
+ event.highlight((Firmament.identifier("hotm_perk_preset")))
}
}
diff --git a/src/main/kotlin/features/texturepack/BakedModelExtra.kt b/src/main/kotlin/features/texturepack/BakedModelExtra.kt
index 32f419a..6305748 100644
--- a/src/main/kotlin/features/texturepack/BakedModelExtra.kt
+++ b/src/main/kotlin/features/texturepack/BakedModelExtra.kt
@@ -1,11 +1,30 @@
-
package moe.nea.firmament.features.texturepack
+import net.fabricmc.fabric.api.renderer.v1.model.WrapperBakedModel as WrapperBakedModelFabric
import net.minecraft.client.render.model.BakedModel
+import net.minecraft.client.render.model.WrapperBakedModel
+import moe.nea.firmament.util.ErrorUtil
interface BakedModelExtra {
+ companion object {
+ @JvmStatic
+ fun cast(originalModel: BakedModel): BakedModelExtra? {
+ var p = originalModel
+ for (i in 0..256) {
+ p = when (p) {
+ is BakedModelExtra -> return p
+ is WrapperBakedModel -> p.wrapped
+ is WrapperBakedModelFabric -> WrapperBakedModelFabric.unwrap(p)
+ else -> break
+ }
+ }
+ ErrorUtil.softError("Could not find a baked model for $originalModel")
+ return null
+ }
+ }
+
var tintOverrides_firmament: TintOverrides?
fun getHeadModel_firmament(): BakedModel?
- fun setHeadModel_firmament(headModel: BakedModel?)
+ fun setHeadModel_firmament(headModel: BakedModel?)
}
diff --git a/src/main/kotlin/features/texturepack/CustomBlockTextures.kt b/src/main/kotlin/features/texturepack/CustomBlockTextures.kt
index a149928..2f7f084 100644
--- a/src/main/kotlin/features/texturepack/CustomBlockTextures.kt
+++ b/src/main/kotlin/features/texturepack/CustomBlockTextures.kt
@@ -244,7 +244,7 @@ object CustomBlockTextures {
.flatMap { it.lookup.values }
.flatten()
.mapTo(mutableSetOf()) { it.replacement.blockModelIdentifier }
- .forEach { event.addNonItemModel(it) }
+ .forEach { event.addNonItemModel(it, it.id) }
}
private fun prepare(manager: ResourceManager): BakedReplacements {
@@ -263,7 +263,7 @@ object CustomBlockTextures {
val island = SkyBlockIsland.forMode(mode)
val islandMpa = map.getOrPut(island, ::mutableMapOf)
for ((blockId, replacement) in json.replacements) {
- val block = MC.defaultRegistries.getWrapperOrThrow(RegistryKeys.BLOCK)
+ val block = MC.defaultRegistries.getOrThrow(RegistryKeys.BLOCK)
.getOptional(RegistryKey.of(RegistryKeys.BLOCK, blockId))
.getOrNull()
if (block == null) {
diff --git a/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt b/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt
index 7b6e62b..54e9e11 100644
--- a/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt
+++ b/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt
@@ -3,13 +3,13 @@
package moe.nea.firmament.features.texturepack
import java.util.Optional
+import java.util.concurrent.atomic.AtomicInteger
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.UseSerializers
-import kotlin.jvm.optionals.getOrNull
-import net.minecraft.item.ArmorMaterial
import net.minecraft.item.ItemStack
+import net.minecraft.item.equipment.EquipmentModel
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.SinglePreparationResourceReloader
import net.minecraft.util.Identifier
@@ -17,90 +17,139 @@ import net.minecraft.util.profiler.Profiler
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.FinalizeResourceManagerEvent
-import moe.nea.firmament.events.subscription.SubscriptionOwner
-import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger
import moe.nea.firmament.util.IdentifierSerializer
import moe.nea.firmament.util.collections.WeakCache
import moe.nea.firmament.util.skyBlockId
-object CustomGlobalArmorOverrides : SubscriptionOwner {
- @Serializable
- data class ArmorOverride(
- @SerialName("item_ids")
- val itemIds: List<String>,
- val layers: List<ArmorOverrideLayer>,
- val overrides: List<ArmorOverrideOverride> = listOf(),
- ) {
- @Transient
- val bakedLayers = bakeLayers(layers)
- }
-
- fun bakeLayers(layers: List<ArmorOverrideLayer>): List<ArmorMaterial.Layer> {
- return layers.map { ArmorMaterial.Layer(it.identifier, it.suffix, it.tint) }
- }
-
- @Serializable
- data class ArmorOverrideLayer(
- val tint: Boolean = false,
- val identifier: Identifier,
- val suffix: String = "",
- )
-
- @Serializable
- data class ArmorOverrideOverride(
- val predicate: FirmamentModelPredicate,
- val layers: List<ArmorOverrideLayer>,
- ) {
- @Transient
- val bakedLayers = bakeLayers(layers)
- }
-
- override val delegateFeature: FirmamentFeature
- get() = CustomSkyBlockTextures
-
- val overrideCache = WeakCache.memoize<ItemStack, Optional<List<ArmorMaterial.Layer>>>("ArmorOverrides") { stack ->
- val id = stack.skyBlockId ?: return@memoize Optional.empty()
- val override = overrides[id.neuItem] ?: return@memoize Optional.empty()
- for (suboverride in override.overrides) {
- if (suboverride.predicate.test(stack)) {
- return@memoize Optional.of(suboverride.bakedLayers)
- }
- }
- return@memoize Optional.of(override.bakedLayers)
- }
-
- @JvmStatic
- fun overrideArmor(stack: ItemStack): List<ArmorMaterial.Layer>? {
- if (!CustomSkyBlockTextures.TConfig.enableArmorOverrides) return null
- return overrideCache.invoke(stack).getOrNull()
- }
-
- var overrides: Map<String, ArmorOverride> = mapOf()
-
- @Subscribe
- fun onStart(event: FinalizeResourceManagerEvent) {
- event.resourceManager.registerReloader(object :
- SinglePreparationResourceReloader<Map<String, ArmorOverride>>() {
- override fun prepare(manager: ResourceManager, profiler: Profiler): Map<String, ArmorOverride> {
- val overrideFiles = manager.findResources("overrides/armor_models") {
- it.namespace == "firmskyblock" && it.path.endsWith(".json")
- }
- val overrides = overrideFiles.mapNotNull {
- Firmament.tryDecodeJsonFromStream<ArmorOverride>(it.value.inputStream).getOrElse { ex ->
- logger.error("Failed to load armor texture override at ${it.key}", ex)
- null
- }
- }
- val associatedMap = overrides.flatMap { obj -> obj.itemIds.map { it to obj } }
- .toMap()
- return associatedMap
- }
-
- override fun apply(prepared: Map<String, ArmorOverride>, manager: ResourceManager, profiler: Profiler) {
- overrides = prepared
- }
- })
- }
+object CustomGlobalArmorOverrides {
+ @Serializable
+ data class ArmorOverride(
+ @SerialName("item_ids")
+ val itemIds: List<String>,
+ val layers: List<ArmorOverrideLayer>? = null,
+ val model: Identifier? = null,
+ val overrides: List<ArmorOverrideOverride> = listOf(),
+ ) {
+ @Transient
+ lateinit var modelIdentifier: Identifier
+ fun bake() {
+ modelIdentifier = bakeModel(model, layers)
+ overrides.forEach { it.bake() }
+ }
+
+ init {
+ require(layers != null || model != null) { "Either model or layers must be specified for armor override" }
+ require(layers == null || model == null) { "Can't specify both model and layers for armor override" }
+ }
+ }
+
+ @Serializable
+ data class ArmorOverrideLayer(
+ val tint: Boolean = false,
+ val identifier: Identifier,
+ val suffix: String = "",
+ )
+
+ @Serializable
+ data class ArmorOverrideOverride(
+ val predicate: FirmamentModelPredicate,
+ val layers: List<ArmorOverrideLayer>? = null,
+ val model: Identifier? = null,
+ ) {
+ init {
+ require(layers != null || model != null) { "Either model or layers must be specified for armor override override" }
+ require(layers == null || model == null) { "Can't specify both model and layers for armor override override" }
+ }
+
+ @Transient
+ lateinit var modelIdentifier: Identifier
+ fun bake() {
+ modelIdentifier = bakeModel(model, layers)
+ }
+ }
+
+
+ val overrideCache = WeakCache.memoize<ItemStack, Optional<Identifier>>("ArmorOverrides") { stack ->
+ val id = stack.skyBlockId ?: return@memoize Optional.empty()
+ val override = overrides[id.neuItem] ?: return@memoize Optional.empty()
+ for (suboverride in override.overrides) {
+ if (suboverride.predicate.test(stack)) {
+ return@memoize Optional.of(suboverride.modelIdentifier)
+ }
+ }
+ return@memoize Optional.of(override.modelIdentifier)
+ }
+
+ var overrides: Map<String, ArmorOverride> = mapOf()
+ private var bakedOverrides: MutableMap<Identifier, EquipmentModel> = mutableMapOf()
+ private val sentinelFirmRunning = AtomicInteger()
+
+ private fun bakeModel(model: Identifier?, layers: List<ArmorOverrideLayer>?): Identifier {
+ require(model == null || layers == null)
+ if (model != null) {
+ return model
+ } else if (layers != null) {
+ val idNumber = sentinelFirmRunning.incrementAndGet()
+ val identifier = Identifier.of("firmament:sentinel/$idNumber")
+ val equipmentLayers = layers.map {
+ EquipmentModel.Layer(
+ it.identifier, if (it.tint) {
+ Optional.of(EquipmentModel.Dyeable(Optional.empty()))
+ } else {
+ Optional.empty()
+ },
+ false
+ )
+ }
+ bakedOverrides[identifier] = EquipmentModel(
+ mapOf(
+ EquipmentModel.LayerType.HUMANOID to equipmentLayers,
+ EquipmentModel.LayerType.HUMANOID_LEGGINGS to equipmentLayers,
+ )
+ )
+ return identifier
+ } else {
+ error("Either model or layers must be non null")
+ }
+ }
+
+
+ @Subscribe
+ fun onStart(event: FinalizeResourceManagerEvent) {
+ event.resourceManager.registerReloader(object :
+ SinglePreparationResourceReloader<Map<String, ArmorOverride>>() {
+ override fun prepare(manager: ResourceManager, profiler: Profiler): Map<String, ArmorOverride> {
+ val overrideFiles = manager.findResources("overrides/armor_models") {
+ it.namespace == "firmskyblock" && it.path.endsWith(".json")
+ }
+ val overrides = overrideFiles.mapNotNull {
+ Firmament.tryDecodeJsonFromStream<ArmorOverride>(it.value.inputStream).getOrElse { ex ->
+ logger.error("Failed to load armor texture override at ${it.key}", ex)
+ null
+ }
+ }
+ val associatedMap = overrides.flatMap { obj -> obj.itemIds.map { it to obj } }
+ .toMap()
+ return associatedMap
+ }
+
+ override fun apply(prepared: Map<String, ArmorOverride>, manager: ResourceManager, profiler: Profiler) {
+ bakedOverrides.clear()
+ prepared.forEach { it.value.bake() }
+ overrides = prepared
+ }
+ })
+ }
+
+ @JvmStatic
+ fun overrideArmor(itemStack: ItemStack): Optional<Identifier> {
+ return overrideCache.invoke(itemStack)
+ }
+
+ @JvmStatic
+ fun overrideArmorLayer(id: Identifier): EquipmentModel? {
+ return bakedOverrides[id]
+ }
}
diff --git a/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt b/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt
index 2771699..a1203df 100644
--- a/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt
+++ b/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt
@@ -146,7 +146,7 @@ object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalText
it.overrides
.asSequence()
.filter { it.predicate.test(stack) }
- .map { models.modelManager.getModel(ModelIdentifier(it.model, "inventory")) }
+ .map { models.getModel(it.model) }
.firstOrNull()
}
.intoOptional()
diff --git a/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt b/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt
index 0d0f8f2..9f641b8 100644
--- a/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt
+++ b/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt
@@ -1,9 +1,11 @@
package moe.nea.firmament.features.texturepack
+import net.minecraft.client.render.model.Baker
import net.minecraft.util.Identifier
interface JsonUnbakedModelFirmExtra {
+ fun storeExtraBaker_firmament(baker: Baker)
fun setHeadModel_firmament(identifier: Identifier?)
fun getHeadModel_firmament(): Identifier?
diff --git a/src/main/kotlin/features/texturepack/TintOverrides.kt b/src/main/kotlin/features/texturepack/TintOverrides.kt
index 8006db8..85fcae4 100644
--- a/src/main/kotlin/features/texturepack/TintOverrides.kt
+++ b/src/main/kotlin/features/texturepack/TintOverrides.kt
@@ -3,7 +3,6 @@ package moe.nea.firmament.features.texturepack
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import moe.nea.firmament.util.ErrorUtil
-import moe.nea.firmament.util.assertNotNullOr
data class TintOverrides(
val layerMap: Map<Int, TintOverride> = mapOf()
@@ -14,21 +13,22 @@ data class TintOverrides(
val EMPTY = TintOverrides()
private val threadLocal = object : ThreadLocal<TintOverrides>() {}
fun enter(overrides: TintOverrides?) {
- ErrorUtil.softCheck("Double entered tintOverrides") {
- threadLocal.get() == null
- }
+ ErrorUtil.softCheck("Double entered tintOverrides",
+ threadLocal.get() == null)
threadLocal.set(overrides ?: EMPTY)
}
fun exit(overrides: TintOverrides?) {
- ErrorUtil.softCheck("Exited with non matching enter tintOverrides") {
- threadLocal.get() == (overrides ?: EMPTY)
- }
+ ErrorUtil.softCheck("Exited with non matching enter tintOverrides",
+ threadLocal.get() == (overrides ?: EMPTY))
threadLocal.remove()
}
- fun getCurrentOverrides() =
- assertNotNullOr(threadLocal.get(), "Got current tintOverrides without entering") { EMPTY }
+ fun getCurrentOverrides(): TintOverrides {
+ return ErrorUtil.notNullOr(threadLocal.get(), "Got current tintOverrides without entering") {
+ EMPTY
+ }
+ }
fun parse(jsonObject: JsonObject): TintOverrides {
val map = mutableMapOf<Int, TintOverride>()
diff --git a/src/main/kotlin/features/world/FairySouls.kt b/src/main/kotlin/features/world/FairySouls.kt
index eec9b04..1263074 100644
--- a/src/main/kotlin/features/world/FairySouls.kt
+++ b/src/main/kotlin/features/world/FairySouls.kt
@@ -6,6 +6,7 @@ import io.github.moulberry.repo.data.Coordinate
import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer
import net.minecraft.text.Text
+import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ProcessChatEvent
@@ -98,9 +99,8 @@ object FairySouls : FirmamentFeature {
fun onWorldRender(it: WorldRenderLastEvent) {
if (!TConfig.displaySouls) return
renderInWorld(it) {
- color(1F, 1F, 0F, 0.8F)
currentMissingSouls.forEach {
- block(it.blockPos)
+ block(it.blockPos, 0x80FFFF00.toInt())
}
color(1f, 0f, 1f, 1f)
currentLocationSouls.forEach {
diff --git a/src/main/kotlin/features/world/Waypoints.kt b/src/main/kotlin/features/world/Waypoints.kt
index d535b4e..16db059 100644
--- a/src/main/kotlin/features/world/Waypoints.kt
+++ b/src/main/kotlin/features/world/Waypoints.kt
@@ -1,5 +1,3 @@
-
-
package moe.nea.firmament.features.world
import com.mojang.brigadier.arguments.IntegerArgumentType
@@ -12,6 +10,7 @@ import kotlin.collections.set
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.seconds
import net.minecraft.command.argument.BlockPosArgumentType
+import net.minecraft.server.command.CommandOutput
import net.minecraft.server.command.ServerCommandSource
import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos
@@ -35,263 +34,273 @@ import moe.nea.firmament.util.TimeMark
import moe.nea.firmament.util.render.RenderInWorldContext
object Waypoints : FirmamentFeature {
- override val identifier: String
- get() = "waypoints"
+ override val identifier: String
+ get() = "waypoints"
- object TConfig : ManagedConfig(identifier, Category.MINING) { // TODO: add to misc
- val tempWaypointDuration by duration("temp-waypoint-duration", 0.seconds, 1.hours) { 30.seconds }
- val showIndex by toggle("show-index") { true }
- val skipToNearest by toggle("skip-to-nearest") { false }
- // TODO: look ahead size
- }
+ object TConfig : ManagedConfig(identifier, Category.MINING) { // TODO: add to misc
+ val tempWaypointDuration by duration("temp-waypoint-duration", 0.seconds, 1.hours) { 30.seconds }
+ val showIndex by toggle("show-index") { true }
+ val skipToNearest by toggle("skip-to-nearest") { false }
+ // TODO: look ahead size
+ }
- data class TemporaryWaypoint(
- val pos: BlockPos,
- val postedAt: TimeMark,
- )
+ data class TemporaryWaypoint(
+ val pos: BlockPos,
+ val postedAt: TimeMark,
+ )
- override val config get() = TConfig
+ override val config get() = TConfig
- val temporaryPlayerWaypointList = mutableMapOf<String, TemporaryWaypoint>()
- val temporaryPlayerWaypointMatcher = "(?i)x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern()
+ val temporaryPlayerWaypointList = mutableMapOf<String, TemporaryWaypoint>()
+ val temporaryPlayerWaypointMatcher = "(?i)x: (-?[0-9]+),? y: (-?[0-9]+),? z: (-?[0-9]+)".toPattern()
- val waypoints = mutableListOf<BlockPos>()
- var ordered = false
- var orderedIndex = 0
+ val waypoints = mutableListOf<BlockPos>()
+ var ordered = false
+ var orderedIndex = 0
- @Serializable
- data class ColeWeightWaypoint(
- val x: Int,
- val y: Int,
- val z: Int,
- val r: Int = 0,
- val g: Int = 0,
- val b: Int = 0,
- )
+ @Serializable
+ data class ColeWeightWaypoint(
+ val x: Int,
+ val y: Int,
+ val z: Int,
+ val r: Int = 0,
+ val g: Int = 0,
+ val b: Int = 0,
+ )
- @Subscribe
- fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) {
- if (waypoints.isEmpty()) return
- RenderInWorldContext.renderInWorld(event) {
- if (!ordered) {
- waypoints.withIndex().forEach {
- color(0f, 0.3f, 0.7f, 0.5f)
- block(it.value)
- color(1f, 1f, 1f, 1f)
- if (TConfig.showIndex)
- withFacingThePlayer(it.value.toCenterPos()) {
- text(Text.literal(it.index.toString()))
- }
- }
- } else {
- orderedIndex %= waypoints.size
- val firstColor = Color.ofRGBA(0, 200, 40, 180)
- color(firstColor)
- tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f)
- waypoints.withIndex().toList()
- .wrappingWindow(orderedIndex, 3)
- .zip(
- listOf(
- firstColor,
- Color.ofRGBA(180, 200, 40, 150),
- Color.ofRGBA(180, 80, 20, 140),
- )
- )
- .reversed()
- .forEach { (waypoint, col) ->
- val (index, pos) = waypoint
- color(col)
- block(pos)
- color(1f, 1f, 1f, 1f)
- if (TConfig.showIndex)
- withFacingThePlayer(pos.toCenterPos()) {
- text(Text.literal(index.toString()))
- }
- }
- }
- }
- }
+ @Subscribe
+ fun onRenderOrderedWaypoints(event: WorldRenderLastEvent) {
+ if (waypoints.isEmpty()) return
+ RenderInWorldContext.renderInWorld(event) {
+ if (!ordered) {
+ waypoints.withIndex().forEach {
+ block(it.value, 0x800050A0.toInt())
+ if (TConfig.showIndex)
+ withFacingThePlayer(it.value.toCenterPos()) {
+ text(Text.literal(it.index.toString()))
+ }
+ }
+ } else {
+ orderedIndex %= waypoints.size
+ val firstColor = Color.ofRGBA(0, 200, 40, 180)
+ color(firstColor)
+ tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f)
+ waypoints.withIndex().toList()
+ .wrappingWindow(orderedIndex, 3)
+ .zip(
+ listOf(
+ firstColor,
+ Color.ofRGBA(180, 200, 40, 150),
+ Color.ofRGBA(180, 80, 20, 140),
+ )
+ )
+ .reversed()
+ .forEach { (waypoint, col) ->
+ val (index, pos) = waypoint
+ block(pos, col.color)
+ if (TConfig.showIndex)
+ withFacingThePlayer(pos.toCenterPos()) {
+ text(Text.literal(index.toString()))
+ }
+ }
+ }
+ }
+ }
- @Subscribe
- fun onTick(event: TickEvent) {
- if (waypoints.isEmpty() || !ordered) return
- orderedIndex %= waypoints.size
- val p = MC.player?.pos ?: return
- if (TConfig.skipToNearest) {
- orderedIndex =
- (waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size
- } else {
- if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) {
- orderedIndex = (orderedIndex + 1) % waypoints.size
- }
- }
- }
+ @Subscribe
+ fun onTick(event: TickEvent) {
+ if (waypoints.isEmpty() || !ordered) return
+ orderedIndex %= waypoints.size
+ val p = MC.player?.pos ?: return
+ if (TConfig.skipToNearest) {
+ orderedIndex =
+ (waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size
+ } else {
+ if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) {
+ orderedIndex = (orderedIndex + 1) % waypoints.size
+ }
+ }
+ }
- @Subscribe
- fun onProcessChat(it: ProcessChatEvent) {
- val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString)
- if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) {
- temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint(
- BlockPos(
- matcher.group(1).toInt(),
- matcher.group(2).toInt(),
- matcher.group(3).toInt(),
- ),
- TimeMark.now()
- )
- }
- }
+ @Subscribe
+ fun onProcessChat(it: ProcessChatEvent) {
+ val matcher = temporaryPlayerWaypointMatcher.matcher(it.unformattedString)
+ if (it.nameHeuristic != null && TConfig.tempWaypointDuration > 0.seconds && matcher.find()) {
+ temporaryPlayerWaypointList[it.nameHeuristic] = TemporaryWaypoint(
+ BlockPos(
+ matcher.group(1).toInt(),
+ matcher.group(2).toInt(),
+ matcher.group(3).toInt(),
+ ),
+ TimeMark.now()
+ )
+ }
+ }
- @Subscribe
- fun onCommand(event: CommandEvent.SubCommand) {
- event.subcommand("waypoint") {
- thenArgument("pos", BlockPosArgumentType.blockPos()) { pos ->
- thenExecute {
- val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer())
- waypoints.add(position)
- source.sendFeedback(
- Text.stringifiedTranslatable(
- "firmament.command.waypoint.added",
- position.x,
- position.y,
- position.z
- )
- )
- }
- }
- }
- event.subcommand("waypoints") {
- thenLiteral("clear") {
- thenExecute {
- waypoints.clear()
- source.sendFeedback(Text.translatable("firmament.command.waypoint.clear"))
- }
- }
- thenLiteral("toggleordered") {
- thenExecute {
- ordered = !ordered
- if (ordered) {
- val p = MC.player?.pos ?: Vec3d.ZERO
- orderedIndex =
- waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0
- }
- source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered"))
- }
- }
- thenLiteral("skip") {
- thenExecute {
- if (ordered && waypoints.isNotEmpty()) {
- orderedIndex = (orderedIndex + 1) % waypoints.size
- source.sendFeedback(Text.translatable("firmament.command.waypoint.skip"))
- } else {
- source.sendError(Text.translatable("firmament.command.waypoint.skip.error"))
- }
- }
- }
- thenLiteral("remove") {
- thenArgument("index", IntegerArgumentType.integer(0)) { indexArg ->
- thenExecute {
- val index = get(indexArg)
- if (index in waypoints.indices) {
- waypoints.removeAt(index)
- source.sendFeedback(Text.stringifiedTranslatable(
- "firmament.command.waypoint.remove",
- index))
- } else {
- source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error"))
- }
- }
- }
- }
- thenLiteral("import") {
- thenExecute {
- val contents = ClipboardUtils.getTextContents()
- val data = try {
- Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents)
- } catch (ex: Exception) {
- Firmament.logger.error("Could not load waypoints from clipboard", ex)
- source.sendError(Text.translatable("firmament.command.waypoint.import.error"))
- return@thenExecute
- }
- waypoints.clear()
- data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) }
- source.sendFeedback(
- Text.stringifiedTranslatable(
- "firmament.command.waypoint.import",
- data.size
- )
- )
- }
- }
- }
- }
+ @Subscribe
+ fun onCommand(event: CommandEvent.SubCommand) {
+ event.subcommand("waypoint") {
+ thenArgument("pos", BlockPosArgumentType.blockPos()) { pos ->
+ thenExecute {
+ val position = pos.get(this).toAbsoluteBlockPos(source.asFakeServer())
+ waypoints.add(position)
+ source.sendFeedback(
+ Text.stringifiedTranslatable(
+ "firmament.command.waypoint.added",
+ position.x,
+ position.y,
+ position.z
+ )
+ )
+ }
+ }
+ }
+ event.subcommand("waypoints") {
+ thenLiteral("clear") {
+ thenExecute {
+ waypoints.clear()
+ source.sendFeedback(Text.translatable("firmament.command.waypoint.clear"))
+ }
+ }
+ thenLiteral("toggleordered") {
+ thenExecute {
+ ordered = !ordered
+ if (ordered) {
+ val p = MC.player?.pos ?: Vec3d.ZERO
+ orderedIndex =
+ waypoints.withIndex().minByOrNull { it.value.getSquaredDistance(p) }?.index ?: 0
+ }
+ source.sendFeedback(Text.translatable("firmament.command.waypoint.ordered.toggle.$ordered"))
+ }
+ }
+ thenLiteral("skip") {
+ thenExecute {
+ if (ordered && waypoints.isNotEmpty()) {
+ orderedIndex = (orderedIndex + 1) % waypoints.size
+ source.sendFeedback(Text.translatable("firmament.command.waypoint.skip"))
+ } else {
+ source.sendError(Text.translatable("firmament.command.waypoint.skip.error"))
+ }
+ }
+ }
+ thenLiteral("remove") {
+ thenArgument("index", IntegerArgumentType.integer(0)) { indexArg ->
+ thenExecute {
+ val index = get(indexArg)
+ if (index in waypoints.indices) {
+ waypoints.removeAt(index)
+ source.sendFeedback(Text.stringifiedTranslatable(
+ "firmament.command.waypoint.remove",
+ index))
+ } else {
+ source.sendError(Text.stringifiedTranslatable("firmament.command.waypoint.remove.error"))
+ }
+ }
+ }
+ }
+ thenLiteral("import") {
+ thenExecute {
+ val contents = ClipboardUtils.getTextContents()
+ val data = try {
+ Firmament.json.decodeFromString<List<ColeWeightWaypoint>>(contents)
+ } catch (ex: Exception) {
+ Firmament.logger.error("Could not load waypoints from clipboard", ex)
+ source.sendError(Text.translatable("firmament.command.waypoint.import.error"))
+ return@thenExecute
+ }
+ waypoints.clear()
+ data.mapTo(waypoints) { BlockPos(it.x, it.y, it.z) }
+ source.sendFeedback(
+ Text.stringifiedTranslatable(
+ "firmament.command.waypoint.import",
+ data.size
+ )
+ )
+ }
+ }
+ }
+ }
- @Subscribe
- fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) {
- temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
- if (temporaryPlayerWaypointList.isEmpty()) return
- RenderInWorldContext.renderInWorld(event) {
- color(1f, 1f, 0f, 1f)
- temporaryPlayerWaypointList.forEach { (player, waypoint) ->
- block(waypoint.pos)
- }
- color(1f, 1f, 1f, 1f)
- temporaryPlayerWaypointList.forEach { (player, waypoint) ->
- val skin =
- MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player }
- ?.skinTextures
- ?.texture
- withFacingThePlayer(waypoint.pos.toCenterPos()) {
- waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player))
- if (skin != null) {
- matrixStack.translate(0F, -20F, 0F)
- // Head front
- texture(
- skin, 16, 16,
- 1 / 8f, 1 / 8f,
- 2 / 8f, 2 / 8f,
- )
- // Head overlay
- texture(
- skin, 16, 16,
- 5 / 8f, 1 / 8f,
- 6 / 8f, 2 / 8f,
- )
- }
- }
- }
- }
- }
+ @Subscribe
+ fun onRenderTemporaryWaypoints(event: WorldRenderLastEvent) {
+ temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
+ if (temporaryPlayerWaypointList.isEmpty()) return
+ RenderInWorldContext.renderInWorld(event) {
+ temporaryPlayerWaypointList.forEach { (player, waypoint) ->
+ block(waypoint.pos, 0xFFFFFF00.toInt())
+ }
+ temporaryPlayerWaypointList.forEach { (player, waypoint) ->
+ val skin =
+ MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player }
+ ?.skinTextures
+ ?.texture
+ withFacingThePlayer(waypoint.pos.toCenterPos()) {
+ waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player))
+ if (skin != null) {
+ matrixStack.translate(0F, -20F, 0F)
+ // Head front
+ texture(
+ skin, 16, 16,
+ 1 / 8f, 1 / 8f,
+ 2 / 8f, 2 / 8f,
+ )
+ // Head overlay
+ texture(
+ skin, 16, 16,
+ 5 / 8f, 1 / 8f,
+ 6 / 8f, 2 / 8f,
+ )
+ }
+ }
+ }
+ }
+ }
- @Subscribe
- fun onWorldReady(event: WorldReadyEvent) {
- temporaryPlayerWaypointList.clear()
- }
+ @Subscribe
+ fun onWorldReady(event: WorldReadyEvent) {
+ temporaryPlayerWaypointList.clear()
+ }
}
fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> {
- val result = ArrayList<E>(windowSize)
- if (startIndex + windowSize < size) {
- result.addAll(subList(startIndex, startIndex + windowSize))
- } else {
- result.addAll(subList(startIndex, size))
- result.addAll(subList(0, minOf(windowSize - (size - startIndex), startIndex)))
- }
- return result
+ val result = ArrayList<E>(windowSize)
+ if (startIndex + windowSize < size) {
+ result.addAll(subList(startIndex, startIndex + windowSize))
+ } else {
+ result.addAll(subList(startIndex, size))
+ result.addAll(subList(0, minOf(windowSize - (size - startIndex), startIndex)))
+ }
+ return result
}
fun FabricClientCommandSource.asFakeServer(): ServerCommandSource {
- val source = this
- return ServerCommandSource(
- source.player,
- source.position,
- source.rotation,
- null,
- 0,
- "FakeServerCommandSource",
- Text.literal("FakeServerCommandSource"),
- null,
- source.player
- )
+ val source = this
+ return ServerCommandSource(
+ object : CommandOutput {
+ override fun sendMessage(message: Text?) {
+ source.player.sendMessage(message, false)
+ }
+
+ override fun shouldReceiveFeedback(): Boolean {
+ return true
+ }
+
+ override fun shouldTrackOutput(): Boolean {
+ return true
+ }
+
+ override fun shouldBroadcastConsoleToOps(): Boolean {
+ return true
+ }
+ },
+ source.position,
+ source.rotation,
+ null,
+ 0,
+ "FakeServerCommandSource",
+ Text.literal("FakeServerCommandSource"),
+ null,
+ source.player
+ )
}
diff --git a/src/main/kotlin/gui/BarComponent.kt b/src/main/kotlin/gui/BarComponent.kt
index 8ef0753..b82c666 100644
--- a/src/main/kotlin/gui/BarComponent.kt
+++ b/src/main/kotlin/gui/BarComponent.kt
@@ -1,4 +1,3 @@
-
package moe.nea.firmament.gui
import com.mojang.blaze3d.systems.RenderSystem
@@ -10,116 +9,115 @@ import io.github.notenoughupdates.moulconfig.observer.GetSetter
import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext
import me.shedaniel.math.Color
import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.render.RenderLayer
import net.minecraft.util.Identifier
import moe.nea.firmament.Firmament
class BarComponent(
- val progress: GetSetter<Double>, val total: GetSetter<Double>,
- val fillColor: Color,
- val emptyColor: Color,
+ val progress: GetSetter<Double>, val total: GetSetter<Double>,
+ val fillColor: Color,
+ val emptyColor: Color,
) : GuiComponent() {
- override fun getWidth(): Int {
- return 80
- }
+ override fun getWidth(): Int {
+ return 80
+ }
- override fun getHeight(): Int {
- return 8
- }
+ override fun getHeight(): Int {
+ return 8
+ }
- data class Texture(
- val identifier: Identifier,
- val u1: Float, val v1: Float,
- val u2: Float, val v2: Float,
- ) {
- fun draw(context: DrawContext, x: Int, y: Int, width: Int, height: Int, color: Color) {
- context.drawTexturedQuad(
- identifier,
- x, y, x + width, x + height, 0,
- u1, u2, v1, v2,
- color.red / 255F,
- color.green / 255F,
- color.blue / 255F,
- color.alpha / 255F,
- )
- }
- }
+ data class Texture(
+ val identifier: Identifier,
+ val u1: Float, val v1: Float,
+ val u2: Float, val v2: Float,
+ ) {
+ fun draw(context: DrawContext, x: Int, y: Int, width: Int, height: Int, color: Color) {
+ context.drawTexturedQuad(
+ RenderLayer::getGuiTextured,
+ identifier,
+ x, y, x + width, x + height,
+ u1, u2, v1, v2,
+ color.color
+ )
+ }
+ }
- companion object {
- val resource = Firmament.identifier("textures/gui/bar.png")
- val left = Texture(resource, 0 / 64F, 0 / 64F, 4 / 64F, 8 / 64F)
- val middle = Texture(resource, 4 / 64F, 0 / 64F, 8 / 64F, 8 / 64F)
- val right = Texture(resource, 8 / 64F, 0 / 64F, 12 / 64F, 8 / 64F)
- val segmentOverlay = Texture(resource, 12 / 64F, 0 / 64F, 15 / 64F, 8 / 64F)
- }
+ companion object {
+ val resource = Firmament.identifier("textures/gui/bar.png")
+ val left = Texture(resource, 0 / 64F, 0 / 64F, 4 / 64F, 8 / 64F)
+ val middle = Texture(resource, 4 / 64F, 0 / 64F, 8 / 64F, 8 / 64F)
+ val right = Texture(resource, 8 / 64F, 0 / 64F, 12 / 64F, 8 / 64F)
+ val segmentOverlay = Texture(resource, 12 / 64F, 0 / 64F, 15 / 64F, 8 / 64F)
+ }
- private fun drawSection(
- context: DrawContext,
- texture: Texture,
- x: Int,
- y: Int,
- width: Int,
- sectionStart: Double,
- sectionEnd: Double
- ) {
- if (sectionEnd < progress.get() && width == 4) {
- texture.draw(context, x, y, 4, 8, fillColor)
- return
- }
- if (sectionStart > progress.get() && width == 4) {
- texture.draw(context, x, y, 4, 8, emptyColor)
- return
- }
- val increasePerPixel = (sectionEnd - sectionStart) / width
- var valueAtPixel = sectionStart
- for (i in (0 until width)) {
- val newTex =
- Texture(texture.identifier, texture.u1 + i / 64F, texture.v1, texture.u1 + (i + 1) / 64F, texture.v2)
- newTex.draw(
- context, x + i, y, 1, 8,
- if (valueAtPixel < progress.get()) fillColor else emptyColor
- )
- valueAtPixel += increasePerPixel
- }
- }
+ private fun drawSection(
+ context: DrawContext,
+ texture: Texture,
+ x: Int,
+ y: Int,
+ width: Int,
+ sectionStart: Double,
+ sectionEnd: Double
+ ) {
+ if (sectionEnd < progress.get() && width == 4) {
+ texture.draw(context, x, y, 4, 8, fillColor)
+ return
+ }
+ if (sectionStart > progress.get() && width == 4) {
+ texture.draw(context, x, y, 4, 8, emptyColor)
+ return
+ }
+ val increasePerPixel = (sectionEnd - sectionStart) / width
+ var valueAtPixel = sectionStart
+ for (i in (0 until width)) {
+ val newTex =
+ Texture(texture.identifier, texture.u1 + i / 64F, texture.v1, texture.u1 + (i + 1) / 64F, texture.v2)
+ newTex.draw(
+ context, x + i, y, 1, 8,
+ if (valueAtPixel < progress.get()) fillColor else emptyColor
+ )
+ valueAtPixel += increasePerPixel
+ }
+ }
- override fun render(context: GuiImmediateContext) {
- val renderContext = (context.renderContext as ModernRenderContext).drawContext
- var i = 0
- val x = 0
- val y = 0
- while (i < context.width - 4) {
- drawSection(
- renderContext,
- if (i == 0) left else middle,
- x + i, y,
- (context.width - (i + 4)).coerceAtMost(4),
- i * total.get() / context.width, (i + 4) * total.get() / context.width
- )
- i += 4
- }
- drawSection(
- renderContext,
- right,
- x + context.width - 4,
- y,
- 4,
- (context.width - 4) * total.get() / context.width,
- total.get()
- )
- RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
+ override fun render(context: GuiImmediateContext) {
+ val renderContext = (context.renderContext as ModernRenderContext).drawContext
+ var i = 0
+ val x = 0
+ val y = 0
+ while (i < context.width - 4) {
+ drawSection(
+ renderContext,
+ if (i == 0) left else middle,
+ x + i, y,
+ (context.width - (i + 4)).coerceAtMost(4),
+ i * total.get() / context.width, (i + 4) * total.get() / context.width
+ )
+ i += 4
+ }
+ drawSection(
+ renderContext,
+ right,
+ x + context.width - 4,
+ y,
+ 4,
+ (context.width - 4) * total.get() / context.width,
+ total.get()
+ )
+ RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
- }
+ }
}
fun Identifier.toMoulConfig(): MyResourceLocation {
- return MyResourceLocation(this.namespace, this.path)
+ return MyResourceLocation(this.namespace, this.path)
}
fun RenderContext.color(color: Color) {
- color(color.red, color.green, color.blue, color.alpha)
+ color(color.red, color.green, color.blue, color.alpha)
}
fun RenderContext.color(red: Int, green: Int, blue: Int, alpha: Int) {
- color(red / 255f, green / 255f, blue / 255f, alpha / 255f)
+ color(red / 255f, green / 255f, blue / 255f, alpha / 255f)
}
diff --git a/src/main/kotlin/gui/entity/EntityRenderer.kt b/src/main/kotlin/gui/entity/EntityRenderer.kt
index 8c7428d..ddb862f 100644
--- a/src/main/kotlin/gui/entity/EntityRenderer.kt
+++ b/src/main/kotlin/gui/entity/EntityRenderer.kt
@@ -1,4 +1,3 @@
-
package moe.nea.firmament.gui.entity
import com.google.gson.Gson
@@ -13,7 +12,9 @@ import net.minecraft.client.gui.screen.ingame.InventoryScreen
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
+import net.minecraft.entity.SpawnReason
import net.minecraft.util.Identifier
+import net.minecraft.world.World
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.assertNotNullOr
import moe.nea.firmament.util.iterate
@@ -21,177 +22,177 @@ import moe.nea.firmament.util.openFirmamentResource
import moe.nea.firmament.util.render.enableScissorWithTranslation
object EntityRenderer {
- val fakeWorld = FakeWorld()
- private fun <T : Entity> t(entityType: EntityType<T>): () -> T {
- return { entityType.create(fakeWorld)!! }
- }
+ val fakeWorld: World get() = MC.lastWorld!!
+ private fun <T : Entity> t(entityType: EntityType<T>): () -> T {
+ return { entityType.create(fakeWorld, SpawnReason.LOAD)!! }
+ }
- val entityIds: Map<String, () -> LivingEntity> = mapOf(
- "Zombie" to t(EntityType.ZOMBIE),
- "Chicken" to t(EntityType.CHICKEN),
- "Slime" to t(EntityType.SLIME),
- "Wolf" to t(EntityType.WOLF),
- "Skeleton" to t(EntityType.SKELETON),
- "Creeper" to t(EntityType.CREEPER),
- "Ocelot" to t(EntityType.OCELOT),
- "Blaze" to t(EntityType.BLAZE),
- "Rabbit" to t(EntityType.RABBIT),
- "Sheep" to t(EntityType.SHEEP),
- "Horse" to t(EntityType.HORSE),
- "Eisengolem" to t(EntityType.IRON_GOLEM),
- "Silverfish" to t(EntityType.SILVERFISH),
- "Witch" to t(EntityType.WITCH),
- "Endermite" to t(EntityType.ENDERMITE),
- "Snowman" to t(EntityType.SNOW_GOLEM),
- "Villager" to t(EntityType.VILLAGER),
- "Guardian" to t(EntityType.GUARDIAN),
- "ArmorStand" to t(EntityType.ARMOR_STAND),
- "Squid" to t(EntityType.SQUID),
- "Bat" to t(EntityType.BAT),
- "Spider" to t(EntityType.SPIDER),
- "CaveSpider" to t(EntityType.CAVE_SPIDER),
- "Pigman" to t(EntityType.ZOMBIFIED_PIGLIN),
- "Ghast" to t(EntityType.GHAST),
- "MagmaCube" to t(EntityType.MAGMA_CUBE),
- "Wither" to t(EntityType.WITHER),
- "Enderman" to t(EntityType.ENDERMAN),
- "Mooshroom" to t(EntityType.MOOSHROOM),
- "WitherSkeleton" to t(EntityType.WITHER_SKELETON),
- "Cow" to t(EntityType.COW),
- "Dragon" to t(EntityType.ENDER_DRAGON),
- "Player" to { makeGuiPlayer(fakeWorld) },
- "Pig" to t(EntityType.PIG),
- "Giant" to t(EntityType.GIANT),
- )
- val entityModifiers: Map<String, EntityModifier> = mapOf(
- "playerdata" to ModifyPlayerSkin,
- "equipment" to ModifyEquipment,
- "riding" to ModifyRiding,
- "charged" to ModifyCharged,
- "witherdata" to ModifyWither,
- "invisible" to ModifyInvisible,
- "age" to ModifyAge,
- "horse" to ModifyHorse,
- "name" to ModifyName,
- )
+ val entityIds: Map<String, () -> LivingEntity> = mapOf(
+ "Zombie" to t(EntityType.ZOMBIE),
+ "Chicken" to t(EntityType.CHICKEN),
+ "Slime" to t(EntityType.SLIME),
+ "Wolf" to t(EntityType.WOLF),
+ "Skeleton" to t(EntityType.SKELETON),
+ "Creeper" to t(EntityType.CREEPER),
+ "Ocelot" to t(EntityType.OCELOT),
+ "Blaze" to t(EntityType.BLAZE),
+ "Rabbit" to t(EntityType.RABBIT),
+ "Sheep" to t(EntityType.SHEEP),
+ "Horse" to t(EntityType.HORSE),
+ "Eisengolem" to t(EntityType.IRON_GOLEM),
+ "Silverfish" to t(EntityType.SILVERFISH),
+ "Witch" to t(EntityType.WITCH),
+ "Endermite" to t(EntityType.ENDERMITE),
+ "Snowman" to t(EntityType.SNOW_GOLEM),
+ "Villager" to t(EntityType.VILLAGER),
+ "Guardian" to t(EntityType.GUARDIAN),
+ "ArmorStand" to t(EntityType.ARMOR_STAND),
+ "Squid" to t(EntityType.SQUID),
+ "Bat" to t(EntityType.BAT),
+ "Spider" to t(EntityType.SPIDER),
+ "CaveSpider" to t(EntityType.CAVE_SPIDER),
+ "Pigman" to t(EntityType.ZOMBIFIED_PIGLIN),
+ "Ghast" to t(EntityType.GHAST),
+ "MagmaCube" to t(EntityType.MAGMA_CUBE),
+ "Wither" to t(EntityType.WITHER),
+ "Enderman" to t(EntityType.ENDERMAN),
+ "Mooshroom" to t(EntityType.MOOSHROOM),
+ "WitherSkeleton" to t(EntityType.WITHER_SKELETON),
+ "Cow" to t(EntityType.COW),
+ "Dragon" to t(EntityType.ENDER_DRAGON),
+ "Player" to { makeGuiPlayer(fakeWorld) },
+ "Pig" to t(EntityType.PIG),
+ "Giant" to t(EntityType.GIANT),
+ )
+ val entityModifiers: Map<String, EntityModifier> = mapOf(
+ "playerdata" to ModifyPlayerSkin,
+ "equipment" to ModifyEquipment,
+ "riding" to ModifyRiding,
+ "charged" to ModifyCharged,
+ "witherdata" to ModifyWither,
+ "invisible" to ModifyInvisible,
+ "age" to ModifyAge,
+ "horse" to ModifyHorse,
+ "name" to ModifyName,
+ )
- val logger = LogManager.getLogger("Firmament.Entity")
- fun applyModifiers(entityId: String, modifiers: List<JsonObject>): LivingEntity? {
- val entityType = assertNotNullOr(entityIds[entityId]) {
- logger.error("Could not create entity with id $entityId")
- return null
- }
- var entity = entityType()
- for (modifierJson in modifiers) {
- val modifier = assertNotNullOr(modifierJson["type"]?.asString?.let(entityModifiers::get)) {
- logger.error("Unknown modifier $modifierJson")
- return null
- }
- entity = modifier.apply(entity, modifierJson)
- }
- return entity
- }
+ val logger = LogManager.getLogger("Firmament.Entity")
+ fun applyModifiers(entityId: String, modifiers: List<JsonObject>): LivingEntity? {
+ val entityType = assertNotNullOr(entityIds[entityId]) {
+ logger.error("Could not create entity with id $entityId")
+ return null
+ }
+ var entity = entityType()
+ for (modifierJson in modifiers) {
+ val modifier = assertNotNullOr(modifierJson["type"]?.asString?.let(entityModifiers::get)) {
+ logger.error("Unknown modifier $modifierJson")
+ return null
+ }
+ entity = modifier.apply(entity, modifierJson)
+ }
+ return entity
+ }
- fun constructEntity(info: JsonObject): LivingEntity? {
- val modifiers = (info["modifiers"] as JsonArray?)?.map { it.asJsonObject } ?: emptyList()
- val entityType = assertNotNullOr(info["entity"]?.asString) {
- logger.error("Missing entity type on entity object")
- return null
- }
- return applyModifiers(entityType, modifiers)
- }
+ fun constructEntity(info: JsonObject): LivingEntity? {
+ val modifiers = (info["modifiers"] as JsonArray?)?.map { it.asJsonObject } ?: emptyList()
+ val entityType = assertNotNullOr(info["entity"]?.asString) {
+ logger.error("Missing entity type on entity object")
+ return null
+ }
+ return applyModifiers(entityType, modifiers)
+ }
- private val gson = Gson()
- fun constructEntity(location: Identifier): LivingEntity? {
- return constructEntity(
- gson.fromJson(
- location.openFirmamentResource().bufferedReader(), JsonObject::class.java
- )
- )
- }
+ private val gson = Gson()
+ fun constructEntity(location: Identifier): LivingEntity? {
+ return constructEntity(
+ gson.fromJson(
+ location.openFirmamentResource().bufferedReader(), JsonObject::class.java
+ )
+ )
+ }
- fun renderEntity(
- entity: LivingEntity,
- renderContext: DrawContext,
- posX: Int,
- posY: Int,
- mouseX: Float,
- mouseY: Float
- ) {
- var bottomOffset = 0.0F
- var currentEntity = entity
- val maxSize = entity.iterate { it.firstPassenger as? LivingEntity }
- .map { it.height }
- .sum()
- while (true) {
- currentEntity.age = MC.player?.age ?: 0
- drawEntity(
- renderContext,
- posX,
- posY,
- posX + 50,
- posY + 80,
- minOf(2F / maxSize, 1F) * 30,
- -bottomOffset,
- mouseX,
- mouseY,
- currentEntity
- )
- val next = currentEntity.firstPassenger as? LivingEntity ?: break
- bottomOffset += currentEntity.getPassengerRidingPos(next).y.toFloat() * 0.75F
- currentEntity = next
- }
- }
+ fun renderEntity(
+ entity: LivingEntity,
+ renderContext: DrawContext,
+ posX: Int,
+ posY: Int,
+ mouseX: Float,
+ mouseY: Float
+ ) {
+ var bottomOffset = 0.0F
+ var currentEntity = entity
+ val maxSize = entity.iterate { it.firstPassenger as? LivingEntity }
+ .map { it.height }
+ .sum()
+ while (true) {
+ currentEntity.age = MC.player?.age ?: 0
+ drawEntity(
+ renderContext,
+ posX,
+ posY,
+ posX + 50,
+ posY + 80,
+ minOf(2F / maxSize, 1F) * 30,
+ -bottomOffset,
+ mouseX,
+ mouseY,
+ currentEntity
+ )
+ val next = currentEntity.firstPassenger as? LivingEntity ?: break
+ bottomOffset += currentEntity.getPassengerRidingPos(next).y.toFloat() * 0.75F
+ currentEntity = next
+ }
+ }
- fun drawEntity(
- context: DrawContext,
- x1: Int,
- y1: Int,
- x2: Int,
- y2: Int,
- size: Float,
- bottomOffset: Float,
- mouseX: Float,
- mouseY: Float,
- entity: LivingEntity
- ) {
- context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
- val centerX = (x1 + x2) / 2f
- val centerY = (y1 + y2) / 2f
- val targetYaw = atan(((centerX - mouseX) / 40.0f).toDouble()).toFloat()
- val targetPitch = atan(((centerY - mouseY) / 40.0f).toDouble()).toFloat()
- val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat())
- val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180))
- rotateToFaceTheFront.mul(rotateToFaceTheCamera)
- val oldBodyYaw = entity.bodyYaw
- val oldYaw = entity.yaw
- val oldPitch = entity.pitch
- val oldPrevHeadYaw = entity.prevHeadYaw
- val oldHeadYaw = entity.headYaw
- entity.bodyYaw = 180.0f + targetYaw * 20.0f
- entity.yaw = 180.0f + targetYaw * 40.0f
- entity.pitch = -targetPitch * 20.0f
- entity.headYaw = entity.yaw
- entity.prevHeadYaw = entity.yaw
- val vector3f = Vector3f(0.0f, entity.height / 2.0f + bottomOffset, 0.0f)
- InventoryScreen.drawEntity(
- context,
- centerX,
- centerY,
- size,
- vector3f,
- rotateToFaceTheFront,
- rotateToFaceTheCamera,
- entity
- )
- entity.bodyYaw = oldBodyYaw
- entity.yaw = oldYaw
- entity.pitch = oldPitch
- entity.prevHeadYaw = oldPrevHeadYaw
- entity.headYaw = oldHeadYaw
- context.disableScissor()
- }
+ fun drawEntity(
+ context: DrawContext,
+ x1: Int,
+ y1: Int,
+ x2: Int,
+ y2: Int,
+ size: Float,
+ bottomOffset: Float,
+ mouseX: Float,
+ mouseY: Float,
+ entity: LivingEntity
+ ) {
+ context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
+ val centerX = (x1 + x2) / 2f
+ val centerY = (y1 + y2) / 2f
+ val targetYaw = atan(((centerX - mouseX) / 40.0f).toDouble()).toFloat()
+ val targetPitch = atan(((centerY - mouseY) / 40.0f).toDouble()).toFloat()
+ val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat())
+ val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180))
+ rotateToFaceTheFront.mul(rotateToFaceTheCamera)
+ val oldBodyYaw = entity.bodyYaw
+ val oldYaw = entity.yaw
+ val oldPitch = entity.pitch
+ val oldPrevHeadYaw = entity.prevHeadYaw
+ val oldHeadYaw = entity.headYaw
+ entity.bodyYaw = 180.0f + targetYaw * 20.0f
+ entity.yaw = 180.0f + targetYaw * 40.0f
+ entity.pitch = -targetPitch * 20.0f
+ entity.headYaw = entity.yaw
+ entity.prevHeadYaw = entity.yaw
+ val vector3f = Vector3f(0.0f, entity.height / 2.0f + bottomOffset, 0.0f)
+ InventoryScreen.drawEntity(
+ context,
+ centerX,
+ centerY,
+ size,
+ vector3f,
+ rotateToFaceTheFront,
+ rotateToFaceTheCamera,
+ entity
+ )
+ entity.bodyYaw = oldBodyYaw
+ entity.yaw = oldYaw
+ entity.pitch = oldPitch
+ entity.prevHeadYaw = oldPrevHeadYaw
+ entity.headYaw = oldHeadYaw
+ context.disableScissor()
+ }
}
diff --git a/src/main/kotlin/gui/entity/FakeWorld.kt b/src/main/kotlin/gui/entity/FakeWorld.kt
index f354d5a..7ec385c 100644
--- a/src/main/kotlin/gui/entity/FakeWorld.kt
+++ b/src/main/kotlin/gui/entity/FakeWorld.kt
@@ -1,38 +1,37 @@
-
package moe.nea.firmament.gui.entity
-import com.mojang.datafixers.util.Pair
-import com.mojang.serialization.Lifecycle
-import java.util.*
+import java.util.UUID
import java.util.function.BooleanSupplier
import java.util.function.Consumer
-import java.util.stream.Stream
-import kotlin.jvm.optionals.getOrNull
-import kotlin.streams.asSequence
import net.minecraft.block.Block
import net.minecraft.block.BlockState
+import net.minecraft.client.gui.screen.world.SelectWorldScreen
import net.minecraft.component.type.MapIdComponent
import net.minecraft.entity.Entity
+import net.minecraft.entity.damage.DamageSource
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.fluid.Fluid
+import net.minecraft.item.FuelRegistry
import net.minecraft.item.map.MapState
+import net.minecraft.particle.ParticleEffect
import net.minecraft.recipe.BrewingRecipeRegistry
-import net.minecraft.recipe.Ingredient
import net.minecraft.recipe.RecipeManager
-import net.minecraft.registry.BuiltinRegistries
+import net.minecraft.recipe.RecipePropertySet
+import net.minecraft.recipe.StonecuttingRecipe
+import net.minecraft.recipe.display.CuttingRecipeDisplay
import net.minecraft.registry.DynamicRegistryManager
-import net.minecraft.registry.Registry
+import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
-import net.minecraft.registry.RegistryWrapper
+import net.minecraft.registry.ServerDynamicRegistryType
import net.minecraft.registry.entry.RegistryEntry
-import net.minecraft.registry.entry.RegistryEntryInfo
-import net.minecraft.registry.entry.RegistryEntryList
-import net.minecraft.registry.entry.RegistryEntryOwner
-import net.minecraft.registry.tag.TagKey
+import net.minecraft.resource.DataConfiguration
+import net.minecraft.resource.ResourcePackManager
import net.minecraft.resource.featuretoggle.FeatureFlags
import net.minecraft.resource.featuretoggle.FeatureSet
import net.minecraft.scoreboard.Scoreboard
+import net.minecraft.server.SaveLoading
+import net.minecraft.server.command.CommandManager
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvent
import net.minecraft.util.Identifier
@@ -43,11 +42,8 @@ import net.minecraft.util.math.Box
import net.minecraft.util.math.ChunkPos
import net.minecraft.util.math.Direction
import net.minecraft.util.math.Vec3d
-import net.minecraft.util.math.random.Random
-import net.minecraft.util.profiler.DummyProfiler
import net.minecraft.world.BlockView
import net.minecraft.world.Difficulty
-import net.minecraft.world.GameRules
import net.minecraft.world.MutableWorldProperties
import net.minecraft.world.World
import net.minecraft.world.biome.Biome
@@ -59,430 +55,284 @@ import net.minecraft.world.chunk.EmptyChunk
import net.minecraft.world.chunk.light.LightingProvider
import net.minecraft.world.entity.EntityLookup
import net.minecraft.world.event.GameEvent
+import net.minecraft.world.explosion.ExplosionBehavior
import net.minecraft.world.tick.OrderedTick
import net.minecraft.world.tick.QueryableTickScheduler
import net.minecraft.world.tick.TickManager
-
-fun <T> makeRegistry(registryWrapper: RegistryWrapper.Impl<T>, key: RegistryKey<out Registry<T>>): Registry<T> {
- val inverseLookup = registryWrapper.streamEntries()
- .asSequence().map { it.value() to it.registryKey() }
- .toMap()
- val idLookup = registryWrapper.streamEntries()
- .asSequence()
- .map { it.registryKey() }
- .withIndex()
- .associate { it.value to it.index }
- val map = registryWrapper.streamEntries().asSequence().map { it.registryKey() to it.value() }.toMap(mutableMapOf())
- val inverseIdLookup = idLookup.asIterable().associate { (k, v) -> v to k }
- return object : Registry<T> {
- override fun get(key: RegistryKey<T>?): T? {
- return registryWrapper.getOptional(key).getOrNull()?.value()
- }
-
- override fun iterator(): MutableIterator<T> {
- return object : MutableIterator<T> {
- val iterator = registryWrapper.streamEntries().iterator()
- override fun hasNext(): Boolean {
- return iterator.hasNext()
- }
-
- override fun next(): T {
- return iterator.next().value()
- }
-
- override fun remove() {
- TODO("Not yet implemented")
- }
- }
- }
-
- override fun getRawId(value: T?): Int {
- return idLookup[inverseLookup[value ?: return -1] ?: return -1] ?: return -1
- }
-
- override fun get(id: Identifier?): T? {
- return get(RegistryKey.of(key, id))
- }
-
- override fun get(index: Int): T? {
- return get(inverseIdLookup[index] ?: return null)
- }
-
- override fun size(): Int {
- return idLookup.size
- }
-
- override fun getKey(): RegistryKey<out Registry<T>> {
- return key
- }
-
- override fun getEntryInfo(key: RegistryKey<T>?): Optional<RegistryEntryInfo> {
- TODO("Not yet implemented")
- }
-
- override fun getLifecycle(): Lifecycle {
- return Lifecycle.stable()
- }
-
- override fun getDefaultEntry(): Optional<RegistryEntry.Reference<T>> {
- return Optional.empty()
- }
-
- override fun getIds(): MutableSet<Identifier> {
- return idLookup.keys.mapTo(mutableSetOf()) { it.value }
- }
-
- override fun getEntrySet(): MutableSet<MutableMap.MutableEntry<RegistryKey<T>, T>> {
- return map.entries
- }
-
- override fun getKeys(): MutableSet<RegistryKey<T>> {
- return map.keys
- }
-
- override fun getRandom(random: Random?): Optional<RegistryEntry.Reference<T>> {
- return registryWrapper.streamEntries().findFirst()
- }
-
- override fun containsId(id: Identifier?): Boolean {
- return idLookup.containsKey(RegistryKey.of(key, id ?: return false))
- }
-
- override fun freeze(): Registry<T> {
- return this
- }
-
- override fun getEntry(rawId: Int): Optional<RegistryEntry.Reference<T>> {
- val x = inverseIdLookup[rawId] ?: return Optional.empty()
- return Optional.of(RegistryEntry.Reference.standAlone(registryWrapper, x))
- }
-
- override fun streamEntries(): Stream<RegistryEntry.Reference<T>> {
- return registryWrapper.streamEntries()
- }
-
- override fun streamTagsAndEntries(): Stream<Pair<TagKey<T>, RegistryEntryList.Named<T>>> {
- return streamTags().map { Pair(it, getOrCreateEntryList(it)) }
- }
-
- override fun streamTags(): Stream<TagKey<T>> {
- return registryWrapper.streamTagKeys()
- }
-
- override fun clearTags() {
- }
-
- override fun getEntryOwner(): RegistryEntryOwner<T> {
- return registryWrapper
- }
-
- override fun getReadOnlyWrapper(): RegistryWrapper.Impl<T> {
- return registryWrapper
- }
-
- override fun populateTags(tagEntries: MutableMap<TagKey<T>, MutableList<RegistryEntry<T>>>?) {
- }
-
- override fun getOrCreateEntryList(tag: TagKey<T>?): RegistryEntryList.Named<T> {
- return getEntryList(tag).orElseGet { RegistryEntryList.of(registryWrapper, tag) }
- }
-
- override fun getEntryList(tag: TagKey<T>?): Optional<RegistryEntryList.Named<T>> {
- return registryWrapper.getOptional(tag ?: return Optional.empty())
- }
-
- override fun getEntry(value: T): RegistryEntry<T> {
- return registryWrapper.getOptional(inverseLookup[value]!!).get()
- }
-
- override fun getEntry(key: RegistryKey<T>?): Optional<RegistryEntry.Reference<T>> {
- return registryWrapper.getOptional(key ?: return Optional.empty())
- }
-
- override fun getEntry(id: Identifier?): Optional<RegistryEntry.Reference<T>> {
- TODO("Not yet implemented")
- }
-
- override fun createEntry(value: T): RegistryEntry.Reference<T> {
- TODO("Not yet implemented")
- }
-
- override fun contains(key: RegistryKey<T>?): Boolean {
- return getEntry(key).isPresent
- }
-
- override fun getId(value: T): Identifier? {
- return (inverseLookup[value] ?: return null).value
- }
-
- override fun getKey(entry: T): Optional<RegistryKey<T>> {
- return Optional.ofNullable(inverseLookup[entry ?: return Optional.empty()])
- }
- }
-}
+import moe.nea.firmament.util.MC
fun createDynamicRegistry(): DynamicRegistryManager.Immutable {
- val wrapperLookup = BuiltinRegistries.createWrapperLookup()
- return object : DynamicRegistryManager.Immutable {
- override fun <E : Any?> getOptional(key: RegistryKey<out Registry<out E>>): Optional<Registry<E>> {
- val lookup = wrapperLookup.getOptionalWrapper(key).getOrNull() ?: return Optional.empty()
- val registry = makeRegistry(lookup, key as RegistryKey<out Registry<E>>)
- return Optional.of(registry)
- }
-
- fun <T> entry(reg: RegistryKey<out Registry<T>>): DynamicRegistryManager.Entry<T> {
- return DynamicRegistryManager.Entry(reg, getOptional(reg).get())
- }
-
- override fun streamAllRegistries(): Stream<DynamicRegistryManager.Entry<*>> {
- return wrapperLookup.streamAllRegistryKeys()
- .map { entry(it as RegistryKey<out Registry<Any>>) }
- }
- }
+ // TODO: use SaveLoading.load() to properly load a full registry
+ return DynamicRegistryManager.of(Registries.REGISTRIES)
}
class FakeWorld(
- registries: DynamicRegistryManager.Immutable = createDynamicRegistry(),
+ registries: DynamicRegistryManager.Immutable = createDynamicRegistry(),
) : World(
- Properties,
- RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")),
- registries,
- registries[RegistryKeys.DIMENSION_TYPE].entryOf(
- RegistryKey.of(
- RegistryKeys.DIMENSION_TYPE,
- Identifier.of("minecraft", "overworld")
- )
- ),
- { DummyProfiler.INSTANCE },
- true,
- false,
- 0, 0
+ Properties,
+ RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")),
+ registries,
+ MC.defaultRegistries.getOrThrow(RegistryKeys.DIMENSION_TYPE)
+ .getOrThrow(RegistryKey.of(RegistryKeys.DIMENSION_TYPE, Identifier.of("minecraft", "overworld"))),
+ true,
+ false,
+ 0L,
+ 0
) {
- object Properties : MutableWorldProperties {
- override fun getSpawnPos(): BlockPos {
- return BlockPos.ORIGIN
- }
+ object Properties : MutableWorldProperties {
+ override fun getSpawnPos(): BlockPos {
+ return BlockPos.ORIGIN
+ }
- override fun getSpawnAngle(): Float {
- return 0F
- }
+ override fun getSpawnAngle(): Float {
+ return 0F
+ }
- override fun getTime(): Long {
- return 0
- }
+ override fun getTime(): Long {
+ return 0
+ }
- override fun getTimeOfDay(): Long {
- return 0
- }
+ override fun getTimeOfDay(): Long {
+ return 0
+ }
- override fun isThundering(): Boolean {
- return false
- }
+ override fun isThundering(): Boolean {
+ return false
+ }
- override fun isRaining(): Boolean {
- return false
- }
+ override fun isRaining(): Boolean {
+ return false
+ }
- override fun setRaining(raining: Boolean) {
- }
+ override fun setRaining(raining: Boolean) {
+ }
- override fun isHardcore(): Boolean {
- return false
- }
-
- override fun getGameRules(): GameRules {
- return GameRules()
- }
-
- override fun getDifficulty(): Difficulty {
- return Difficulty.HARD
- }
-
- override fun isDifficultyLocked(): Boolean {
- return false
- }
-
- override fun setSpawnPos(pos: BlockPos?, angle: Float) {}
- }
+ override fun isHardcore(): Boolean {
+ return false
+ }
+
+ override fun getDifficulty(): Difficulty {
+ return Difficulty.HARD
+ }
+
+ override fun isDifficultyLocked(): Boolean {
+ return false
+ }
+
+ override fun setSpawnPos(pos: BlockPos?, angle: Float) {}
+ }
+
+ override fun getPlayers(): List<PlayerEntity> {
+ return emptyList()
+ }
- override fun getPlayers(): List<PlayerEntity> {
- return emptyList()
- }
-
- override fun getBrightness(direction: Direction?, shaded: Boolean): Float {
- return 1f
- }
-
- override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> {
- return registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS)
- }
-
- override fun getEnabledFeatures(): FeatureSet {
- return FeatureFlags.VANILLA_FEATURES
- }
-
- class FakeTickScheduler<T> : QueryableTickScheduler<T> {
- override fun scheduleTick(orderedTick: OrderedTick<T>?) {
- }
-
- override fun isQueued(pos: BlockPos?, type: T): Boolean {
- return true
- }
-
- override fun getTickCount(): Int {
- return 0
- }
-
- override fun isTicking(pos: BlockPos?, type: T): Boolean {
- return true
- }
-
- }
-
- override fun getBlockTickScheduler(): QueryableTickScheduler<Block> {
- return FakeTickScheduler()
- }
-
- override fun getFluidTickScheduler(): QueryableTickScheduler<Fluid> {
- return FakeTickScheduler()
- }
-
-
- class FakeChunkManager(val world: FakeWorld) : ChunkManager() {
- override fun getChunk(x: Int, z: Int, leastStatus: ChunkStatus?, create: Boolean): Chunk {
- return EmptyChunk(
- world,
- ChunkPos(x, z),
- world.registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS)
- )
- }
-
- override fun getWorld(): BlockView {
- return world
- }
-
- override fun tick(shouldKeepTicking: BooleanSupplier?, tickChunks: Boolean) {
- }
-
- override fun getDebugString(): String {
- return "FakeChunkManager"
- }
-
- override fun getLoadedChunkCount(): Int {
- return 0
- }
-
- override fun getLightingProvider(): LightingProvider {
- return FakeLightingProvider(this)
- }
- }
-
- class FakeLightingProvider(chunkManager: FakeChunkManager) : LightingProvider(chunkManager, false, false)
-
- override fun getChunkManager(): ChunkManager {
- return FakeChunkManager(this)
- }
-
- override fun playSound(
- source: PlayerEntity?,
- x: Double,
- y: Double,
- z: Double,
- sound: RegistryEntry<SoundEvent>?,
- category: SoundCategory?,
- volume: Float,
- pitch: Float,
- seed: Long
- ) {
- }
-
- override fun syncWorldEvent(player: PlayerEntity?, eventId: Int, pos: BlockPos?, data: Int) {
- }
-
- override fun emitGameEvent(event: RegistryEntry<GameEvent>?, emitterPos: Vec3d?, emitter: GameEvent.Emitter?) {
- }
-
- override fun updateListeners(pos: BlockPos?, oldState: BlockState?, newState: BlockState?, flags: Int) {
- }
-
- override fun playSoundFromEntity(
- source: PlayerEntity?,
- entity: Entity?,
- sound: RegistryEntry<SoundEvent>?,
- category: SoundCategory?,
- volume: Float,
- pitch: Float,
- seed: Long
- ) {
- }
-
- override fun asString(): String {
- return "FakeWorld"
- }
-
- override fun getEntityById(id: Int): Entity? {
- return null
- }
-
- override fun getTickManager(): TickManager {
- return TickManager()
- }
-
- override fun getMapState(id: MapIdComponent?): MapState? {
- return null
- }
-
- override fun putMapState(id: MapIdComponent?, state: MapState?) {
- }
-
- override fun increaseAndGetMapId(): MapIdComponent {
- return MapIdComponent(0)
- }
-
- override fun setBlockBreakingInfo(entityId: Int, pos: BlockPos?, progress: Int) {
- }
-
- override fun getScoreboard(): Scoreboard {
- return Scoreboard()
- }
-
- override fun getRecipeManager(): RecipeManager {
- return RecipeManager(registryManager)
- }
-
- object FakeEntityLookup : EntityLookup<Entity> {
- override fun get(id: Int): Entity? {
- return null
- }
-
- override fun get(uuid: UUID?): Entity? {
- return null
- }
-
- override fun iterate(): MutableIterable<Entity> {
- return mutableListOf()
- }
-
- override fun <U : Entity?> forEachIntersects(
- filter: TypeFilter<Entity, U>?,
- box: Box?,
- consumer: LazyIterationConsumer<U>?
- ) {
- }
-
- override fun forEachIntersects(box: Box?, action: Consumer<Entity>?) {
- }
-
- override fun <U : Entity?> forEach(filter: TypeFilter<Entity, U>?, consumer: LazyIterationConsumer<U>?) {
- }
-
- }
-
- override fun getEntityLookup(): EntityLookup<Entity> {
- return FakeEntityLookup
- }
-
- override fun getBrewingRecipeRegistry(): BrewingRecipeRegistry {
- return BrewingRecipeRegistry.EMPTY
- }
+ override fun getBrightness(direction: Direction?, shaded: Boolean): Float {
+ return 1f
+ }
+
+ override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> {
+ return registryManager.getOptionalEntry(BiomeKeys.PLAINS).get()
+ }
+
+ override fun getSeaLevel(): Int {
+ return 0
+ }
+
+ override fun getEnabledFeatures(): FeatureSet {
+ return FeatureFlags.VANILLA_FEATURES
+ }
+
+ class FakeTickScheduler<T> : QueryableTickScheduler<T> {
+ override fun scheduleTick(orderedTick: OrderedTick<T>?) {
+ }
+
+ override fun isQueued(pos: BlockPos?, type: T): Boolean {
+ return true
+ }
+
+ override fun getTickCount(): Int {
+ return 0
+ }
+
+ override fun isTicking(pos: BlockPos?, type: T): Boolean {
+ return true
+ }
+
+ }
+
+ override fun getBlockTickScheduler(): QueryableTickScheduler<Block> {
+ return FakeTickScheduler()
+ }
+
+ override fun getFluidTickScheduler(): QueryableTickScheduler<Fluid> {
+ return FakeTickScheduler()
+ }
+
+
+ class FakeChunkManager(val world: FakeWorld) : ChunkManager() {
+ override fun getChunk(x: Int, z: Int, leastStatus: ChunkStatus?, create: Boolean): Chunk {
+ return EmptyChunk(
+ world,
+ ChunkPos(x, z),
+ world.registryManager.getOptionalEntry(BiomeKeys.PLAINS).get()
+ )
+ }
+
+ override fun getWorld(): BlockView {
+ return world
+ }
+
+ override fun tick(shouldKeepTicking: BooleanSupplier?, tickChunks: Boolean) {
+ }
+
+ override fun getDebugString(): String {
+ return "FakeChunkManager"
+ }
+
+ override fun getLoadedChunkCount(): Int {
+ return 0
+ }
+
+ override fun getLightingProvider(): LightingProvider {
+ return FakeLightingProvider(this)
+ }
+ }
+
+ class FakeLightingProvider(chunkManager: FakeChunkManager) : LightingProvider(chunkManager, false, false)
+
+ override fun getChunkManager(): ChunkManager {
+ return FakeChunkManager(this)
+ }
+
+ override fun playSound(
+ source: PlayerEntity?,
+ x: Double,
+ y: Double,
+ z: Double,
+ sound: RegistryEntry<SoundEvent>?,
+ category: SoundCategory?,
+ volume: Float,
+ pitch: Float,
+ seed: Long
+ ) {
+ }
+
+ override fun syncWorldEvent(player: PlayerEntity?, eventId: Int, pos: BlockPos?, data: Int) {
+ }
+
+ override fun emitGameEvent(event: RegistryEntry<GameEvent>?, emitterPos: Vec3d?, emitter: GameEvent.Emitter?) {
+ }
+
+ override fun updateListeners(pos: BlockPos?, oldState: BlockState?, newState: BlockState?, flags: Int) {
+ }
+
+ override fun playSoundFromEntity(
+ source: PlayerEntity?,
+ entity: Entity?,
+ sound: RegistryEntry<SoundEvent>?,
+ category: SoundCategory?,
+ volume: Float,
+ pitch: Float,
+ seed: Long
+ ) {
+ }
+
+ override fun createExplosion(
+ entity: Entity?,
+ damageSource: DamageSource?,
+ behavior: ExplosionBehavior?,
+ x: Double,
+ y: Double,
+ z: Double,
+ power: Float,
+ createFire: Boolean,
+ explosionSourceType: ExplosionSourceType?,
+ smallParticle: ParticleEffect?,
+ largeParticle: ParticleEffect?,
+ soundEvent: RegistryEntry<SoundEvent>?
+ ) {
+ TODO("Not yet implemented")
+ }
+
+ override fun asString(): String {
+ return "FakeWorld"
+ }
+
+ override fun getEntityById(id: Int): Entity? {
+ return null
+ }
+
+ override fun getTickManager(): TickManager {
+ return TickManager()
+ }
+
+ override fun getMapState(id: MapIdComponent?): MapState? {
+ return null
+ }
+
+ override fun putMapState(id: MapIdComponent?, state: MapState?) {
+ }
+
+ override fun increaseAndGetMapId(): MapIdComponent {
+ return MapIdComponent(0)
+ }
+
+ override fun setBlockBreakingInfo(entityId: Int, pos: BlockPos?, progress: Int) {
+ }
+
+ override fun getScoreboard(): Scoreboard {
+ return Scoreboard()
+ }
+
+ override fun getRecipeManager(): RecipeManager {
+ return object : RecipeManager {
+ override fun getPropertySet(key: RegistryKey<RecipePropertySet>?): RecipePropertySet {
+ return RecipePropertySet.EMPTY
+ }
+
+ override fun getStonecutterRecipes(): CuttingRecipeDisplay.Grouping<StonecuttingRecipe> {
+ return CuttingRecipeDisplay.Grouping.empty()
+ }
+ }
+ }
+
+ object FakeEntityLookup : EntityLookup<Entity> {
+ override fun get(id: Int): Entity? {
+ return null
+ }
+
+ override fun get(uuid: UUID?): Entity? {
+ return null
+ }
+
+ override fun iterate(): MutableIterable<Entity> {
+ return mutableListOf()
+ }
+
+ override fun <U : Entity?> forEachIntersects(
+ filter: TypeFilter<Entity, U>?,
+ box: Box?,
+ consumer: LazyIterationConsumer<U>?
+ ) {
+ }
+
+ override fun forEachIntersects(box: Box?, action: Consumer<Entity>?) {
+ }
+
+ override fun <U : Entity?> forEach(filter: TypeFilter<Entity, U>?, consumer: LazyIterationConsumer<U>?) {
+ }
+
+ }
+
+ override fun getEntityLookup(): EntityLookup<Entity> {
+ return FakeEntityLookup
+ }
+
+ override fun getBrewingRecipeRegistry(): BrewingRecipeRegistry {
+ return BrewingRecipeRegistry.EMPTY
+ }
+
+ override fun getFuelRegistry(): FuelRegistry {
+ TODO("Not yet implemented")
+ }
}
diff --git a/src/main/kotlin/gui/entity/GuiPlayer.kt b/src/main/kotlin/gui/entity/GuiPlayer.kt
index d00b44d..aa0bea8 100644
--- a/src/main/kotlin/gui/entity/GuiPlayer.kt
+++ b/src/main/kotlin/gui/entity/GuiPlayer.kt
@@ -1,8 +1,7 @@
-
package moe.nea.firmament.gui.entity
import com.mojang.authlib.GameProfile
-import java.util.*
+import java.util.UUID
import net.minecraft.client.network.AbstractClientPlayerEntity
import net.minecraft.client.util.DefaultSkinHelper
import net.minecraft.client.util.SkinTextures
@@ -15,40 +14,40 @@ import net.minecraft.world.World
/**
* @see moe.nea.firmament.init.EarlyRiser
*/
-fun makeGuiPlayer(world: FakeWorld): GuiPlayer {
- val constructor = GuiPlayer::class.java.getDeclaredConstructor(
- World::class.java,
- BlockPos::class.java,
- Float::class.javaPrimitiveType,
- GameProfile::class.java
- )
- return constructor.newInstance(world, BlockPos.ORIGIN, 0F, GameProfile(UUID.randomUUID(), "Linnea"))
+fun makeGuiPlayer(world: World): GuiPlayer {
+ val constructor = GuiPlayer::class.java.getDeclaredConstructor(
+ World::class.java,
+ BlockPos::class.java,
+ Float::class.javaPrimitiveType,
+ GameProfile::class.java
+ )
+ return constructor.newInstance(world, BlockPos.ORIGIN, 0F, GameProfile(UUID.randomUUID(), "Linnea"))
}
class GuiPlayer(world: ClientWorld?, profile: GameProfile?) : AbstractClientPlayerEntity(world, profile) {
- override fun isSpectator(): Boolean {
- return false
- }
+ override fun isSpectator(): Boolean {
+ return false
+ }
- override fun isCreative(): Boolean {
- return false
- }
+ override fun isCreative(): Boolean {
+ return false
+ }
- override fun shouldRenderName(): Boolean {
- return false
- }
+ override fun shouldRenderName(): Boolean {
+ return false
+ }
- var skinTexture: Identifier = DefaultSkinHelper.getSkinTextures(this.getUuid()).texture
- var capeTexture: Identifier? = null
- var model: Model = Model.WIDE
- override fun getSkinTextures(): SkinTextures {
- return SkinTextures(
- skinTexture,
- null,
- capeTexture,
- null,
- model,
- true
- )
- }
+ var skinTexture: Identifier = DefaultSkinHelper.getSkinTextures(this.getUuid()).texture
+ var capeTexture: Identifier? = null
+ var model: Model = Model.WIDE
+ override fun getSkinTextures(): SkinTextures {
+ return SkinTextures(
+ skinTexture,
+ null,
+ capeTexture,
+ null,
+ model,
+ true
+ )
+ }
}
diff --git a/src/main/kotlin/gui/entity/ModifyHorse.kt b/src/main/kotlin/gui/entity/ModifyHorse.kt
index 8ac011b..f094ca4 100644
--- a/src/main/kotlin/gui/entity/ModifyHorse.kt
+++ b/src/main/kotlin/gui/entity/ModifyHorse.kt
@@ -8,6 +8,7 @@ import kotlin.experimental.inv
import kotlin.experimental.or
import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
+import net.minecraft.entity.SpawnReason
import net.minecraft.entity.passive.AbstractHorseEntity
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
@@ -19,11 +20,11 @@ object ModifyHorse : EntityModifier {
var entity: AbstractHorseEntity = entity
info["kind"]?.let {
entity = when (it.asString) {
- "skeleton" -> EntityType.SKELETON_HORSE.create(fakeWorld)!!
- "zombie" -> EntityType.ZOMBIE_HORSE.create(fakeWorld)!!
- "mule" -> EntityType.MULE.create(fakeWorld)!!
- "donkey" -> EntityType.DONKEY.create(fakeWorld)!!
- "horse" -> EntityType.HORSE.create(fakeWorld)!!
+ "skeleton" -> EntityType.SKELETON_HORSE.create(fakeWorld, SpawnReason.LOAD)!!
+ "zombie" -> EntityType.ZOMBIE_HORSE.create(fakeWorld, SpawnReason.LOAD)!!
+ "mule" -> EntityType.MULE.create(fakeWorld, SpawnReason.LOAD)!!
+ "donkey" -> EntityType.DONKEY.create(fakeWorld, SpawnReason.LOAD)!!
+ "horse" -> EntityType.HORSE.create(fakeWorld, SpawnReason.LOAD)!!
else -> error("Unknown horse kind $it")
}
}
diff --git a/src/main/kotlin/repo/RepoDownloadManager.kt b/src/main/kotlin/repo/RepoDownloadManager.kt
index d674f23..3efd83b 100644
--- a/src/main/kotlin/repo/RepoDownloadManager.kt
+++ b/src/main/kotlin/repo/RepoDownloadManager.kt
@@ -5,7 +5,7 @@ package moe.nea.firmament.repo
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsChannel
-import io.ktor.utils.io.jvm.nio.copyTo
+import io.ktor.utils.io.copyTo
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Path
diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt
index c052fb9..725642e 100644
--- a/src/main/kotlin/repo/RepoManager.kt
+++ b/src/main/kotlin/repo/RepoManager.kt
@@ -9,10 +9,12 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import kotlinx.coroutines.launch
import net.minecraft.client.MinecraftClient
import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket
+import net.minecraft.recipe.display.CuttingRecipeDisplay
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.util.MC
import moe.nea.firmament.util.MinecraftDispatcher
import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.tr
@@ -77,7 +79,7 @@ object RepoManager {
private fun trySendClientboundUpdateRecipesPacket(): Boolean {
return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes(
- SynchronizeRecipesS2CPacket(mutableListOf())
+ SynchronizeRecipesS2CPacket(mutableMapOf(), CuttingRecipeDisplay.Grouping.empty())
) != null
}
@@ -92,7 +94,7 @@ object RepoManager {
fun launchAsyncUpdate(force: Boolean = false) {
Firmament.coroutineScope.launch {
- ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper boundy bar
+ ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper bouncy bar
ItemCache.ReloadProgressHud.isEnabled = true
try {
RepoDownloadManager.downloadUpdate(force)
@@ -112,7 +114,7 @@ object RepoManager {
ItemCache.ReloadProgressHud.isEnabled = true
neuRepo.reload()
} catch (exc: NEURepositoryException) {
- MinecraftClient.getInstance().player?.sendMessage(
+ MC.sendChat(
tr("firmament.repo.reloadfail",
"Failed to reload repository. This will result in some mod features not working.")
)
diff --git a/src/main/kotlin/repo/SBItemStack.kt b/src/main/kotlin/repo/SBItemStack.kt
index 281075d..18126ee 100644
--- a/src/main/kotlin/repo/SBItemStack.kt
+++ b/src/main/kotlin/repo/SBItemStack.kt
@@ -1,9 +1,14 @@
package moe.nea.firmament.repo
+import com.mojang.serialization.Codec
+import com.mojang.serialization.codecs.RecordCodecBuilder
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.network.RegistryByteBuf
+import net.minecraft.network.codec.PacketCodec
+import net.minecraft.network.codec.PacketCodecs
import net.minecraft.text.Text
import net.minecraft.util.Formatting
import moe.nea.firmament.repo.ItemCache.asItemStack
@@ -40,6 +45,21 @@ data class SBItemStack constructor(
}
companion object {
+ val PACKET_CODEC: PacketCodec<in RegistryByteBuf, SBItemStack> = PacketCodec.tuple(
+ SkyblockId.PACKET_CODEC, { it.skyblockId },
+ PacketCodecs.VAR_INT, { it.stackSize },
+ { id, count -> SBItemStack(id, count) }
+ )
+ val CODEC: Codec<SBItemStack> = RecordCodecBuilder.create {
+ it.group(
+ SkyblockId.CODEC.fieldOf("skyblockId").forGetter { it.skyblockId },
+ Codec.INT.fieldOf("count").forGetter { it.stackSize },
+ ).apply(it) { id, count ->
+ SBItemStack(id, count)
+ }
+ }
+ val EMPTY = SBItemStack(SkyblockId.NULL, 0)
+
operator fun invoke(itemStack: ItemStack): SBItemStack {
val skyblockId = itemStack.skyBlockId ?: SkyblockId.NULL
return SBItemStack(
@@ -114,6 +134,8 @@ data class SBItemStack constructor(
val itemStack = itemStack_ ?: run {
if (skyblockId == SkyblockId.COINS)
return@run ItemCache.coinItem(stackSize).also { it.appendLore(extraLore) }
+ if (stackSize == 0)
+ return@run ItemStack.EMPTY
val replacementData = mutableMapOf<String, String>()
injectReplacementDataForPets(replacementData)
return@run neuItem.asItemStack(idHint = skyblockId, replacementData)
diff --git a/src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt b/src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt
new file mode 100644
index 0000000..9a1aea5
--- /dev/null
+++ b/src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt
@@ -0,0 +1,19 @@
+package moe.nea.firmament.repo.recipes
+
+import io.github.moulberry.repo.NEURepository
+import io.github.moulberry.repo.data.NEURecipe
+import me.shedaniel.math.Rectangle
+import net.minecraft.item.ItemStack
+import net.minecraft.text.Text
+import net.minecraft.util.Identifier
+import moe.nea.firmament.repo.SBItemStack
+
+interface GenericRecipeRenderer<T : NEURecipe> {
+ fun render(recipe: T, bounds: Rectangle, layouter: RecipeLayouter)
+ fun getInputs(recipe: T): Collection<SBItemStack>
+ fun getOutputs(recipe: T): Collection<SBItemStack>
+ val icon: ItemStack
+ val title: Text
+ val identifier: Identifier
+ fun findAllRecipes(neuRepository: NEURepository): Iterable<T>
+}
diff --git a/src/main/kotlin/repo/recipes/RecipeLayouter.kt b/src/main/kotlin/repo/recipes/RecipeLayouter.kt
new file mode 100644
index 0000000..109bff5
--- /dev/null
+++ b/src/main/kotlin/repo/recipes/RecipeLayouter.kt
@@ -0,0 +1,33 @@
+package moe.nea.firmament.repo.recipes
+
+import io.github.notenoughupdates.moulconfig.gui.GuiComponent
+import net.minecraft.text.Text
+import moe.nea.firmament.repo.SBItemStack
+
+interface RecipeLayouter {
+ enum class SlotKind {
+ SMALL_INPUT,
+ SMALL_OUTPUT,
+
+ /**
+ * Create a bigger background and mark the slot as output. The coordinates should still refer the upper left corner of the item stack, not of the bigger background.
+ */
+ BIG_OUTPUT,
+ }
+
+ fun createItemSlot(
+ x: Int, y: Int,
+ content: SBItemStack?,
+ slotKind: SlotKind,
+ )
+
+ fun createLabel(
+ x: Int, y: Int,
+ text: Text
+ )
+
+ fun createArrow(x: Int, y: Int)
+
+ fun createMoulConfig(x: Int, y: Int, w: Int, h: Int, component: GuiComponent)
+}
+
diff --git a/src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt b/src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt
new file mode 100644
index 0000000..fd0c750
--- /dev/null
+++ b/src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt
@@ -0,0 +1,50 @@
+package moe.nea.firmament.repo.recipes
+
+import io.github.moulberry.repo.NEURepository
+import io.github.moulberry.repo.data.NEUCraftingRecipe
+import me.shedaniel.math.Point
+import me.shedaniel.math.Rectangle
+import net.minecraft.block.Blocks
+import net.minecraft.item.ItemStack
+import net.minecraft.text.Text
+import net.minecraft.util.Identifier
+import moe.nea.firmament.Firmament
+import moe.nea.firmament.repo.SBItemStack
+import moe.nea.firmament.util.tr
+
+class SBCraftingRecipeRenderer : GenericRecipeRenderer<NEUCraftingRecipe> {
+ override fun render(recipe: NEUCraftingRecipe, bounds: Rectangle, layouter: RecipeLayouter) {
+ val point = Point(bounds.centerX - 58, bounds.centerY - 27)
+ layouter.createArrow(point.x + 60, point.y + 18)
+ for (i in 0 until 3) {
+ for (j in 0 until 3) {
+ val item = recipe.inputs[i + j * 3]
+ layouter.createItemSlot(point.x + 1 + i * 18,
+ point.y + 1 + j * 18,
+ SBItemStack(item),
+ RecipeLayouter.SlotKind.SMALL_INPUT)
+ }
+ }
+ layouter.createItemSlot(
+ point.x + 95, point.y + 19,
+ SBItemStack(recipe.output),
+ RecipeLayouter.SlotKind.BIG_OUTPUT
+ )
+ }
+
+ override fun getInputs(recipe: NEUCraftingRecipe): Collection<SBItemStack> {
+ return recipe.allInputs.mapNotNull { SBItemStack(it) }
+ }
+
+ override fun getOutputs(recipe: NEUCraftingRecipe): Collection<SBItemStack> {
+ return SBItemStack(recipe.output)?.let(::listOf) ?: emptyList()
+ }
+
+ override fun findAllRecipes(neuRepository: NEURepository): Iterable<NEUCraftingRecipe> {
+ return neuRepository.items.items.values.flatMap { it.recipes }.filterIsInstance<NEUCraftingRecipe>()
+ }
+
+ override val icon: ItemStack = ItemStack(Blocks.CRAFTING_TABLE)
+ override val title: Text = tr("firmament.category.crafting", "SkyBlock Crafting")
+ override val identifier: Identifier = Firmament.identifier("crafting_recipe")
+}
diff --git a/src/main/kotlin/util/ErrorUtil.kt b/src/main/kotlin/util/ErrorUtil.kt
index afecf25..b06093b 100644
--- a/src/main/kotlin/util/ErrorUtil.kt
+++ b/src/main/kotlin/util/ErrorUtil.kt
@@ -1,25 +1,46 @@
+@file:OptIn(ExperimentalContracts::class)
+
package moe.nea.firmament.util
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.InvocationKind
+import kotlin.contracts.contract
import moe.nea.firmament.Firmament
+@Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame
object ErrorUtil {
var aggressiveErrors = run {
Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") } || Firmament.DEBUG
+ || ErrorUtil::class.java.desiredAssertionStatus()
+ }
+
+ inline fun softCheck(message: String, check: Boolean) {
+ if (!check) softError(message)
}
- inline fun softCheck(message: String, func: () -> Boolean) {
+ inline fun lazyCheck(message: String, func: () -> Boolean) {
+ contract {
+ callsInPlace(func, InvocationKind.AT_MOST_ONCE)
+ }
if (!aggressiveErrors) return
if (func()) return
error(message)
}
- @Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame
+ inline fun softError(message: String, exception: Throwable) {
+ if (aggressiveErrors) throw IllegalStateException(message, exception)
+ else Firmament.logger.error(message, exception)
+ }
+
inline fun softError(message: String) {
if (aggressiveErrors) error(message)
else Firmament.logger.error(message)
}
inline fun <T : Any> notNullOr(nullable: T?, message: String, orElse: () -> T): T {
+ contract {
+ callsInPlace(orElse, InvocationKind.AT_MOST_ONCE)
+ }
if (nullable == null) {
softError(message)
return orElse()
diff --git a/src/main/kotlin/util/MC.kt b/src/main/kotlin/util/MC.kt
index fc42be9..1b7739f 100644
--- a/src/main/kotlin/util/MC.kt
+++ b/src/main/kotlin/util/MC.kt
@@ -3,9 +3,13 @@ package moe.nea.firmament.util
import io.github.moulberry.repo.data.Coordinate
import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.client.MinecraftClient
+import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.HandledScreen
-import net.minecraft.client.option.GameOptions
+import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.render.WorldRenderer
+import net.minecraft.client.render.item.ItemRenderer
+import net.minecraft.client.world.ClientWorld
+import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
import net.minecraft.registry.BuiltinRegistries
@@ -14,7 +18,9 @@ import net.minecraft.registry.RegistryWrapper
import net.minecraft.resource.ReloadableResourceManagerImpl
import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos
+import net.minecraft.world.World
import moe.nea.firmament.events.TickEvent
+import moe.nea.firmament.events.WorldReadyEvent
object MC {
@@ -29,6 +35,9 @@ object MC {
(nextTickTodos.poll() ?: break).invoke()
}
}
+ WorldReadyEvent.subscribe("MC:ready") {
+ this.lastWorld
+ }
}
fun sendChat(text: Text) {
@@ -69,6 +78,7 @@ object MC {
inline val resourceManager get() = (instance.resourceManager as ReloadableResourceManagerImpl)
+ inline val itemRenderer: ItemRenderer get() = instance.itemRenderer
inline val worldRenderer: WorldRenderer get() = instance.worldRenderer
inline val networkHandler get() = player?.networkHandler
inline val instance get() = MinecraftClient.getInstance()
@@ -79,11 +89,11 @@ object MC {
inline val inGameHud get() = instance.inGameHud
inline val font get() = instance.textRenderer
inline val soundManager get() = instance.soundManager
- inline val player get() = instance.player
- inline val camera get() = instance.cameraEntity
+ inline val player: ClientPlayerEntity? get() = instance.player
+ inline val camera: Entity? get() = instance.cameraEntity
inline val guiAtlasManager get() = instance.guiAtlasManager
- inline val world get() = instance.world
- inline var screen
+ inline val world: ClientWorld? get() = instance.world
+ inline var screen: Screen?
get() = instance.currentScreen
set(value) = instance.setScreen(value)
val screenName get() = screen?.title?.unformattedString?.trim()
@@ -92,7 +102,13 @@ object MC {
inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager
val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup()
inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries
- val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getWrapperOrThrow(RegistryKeys.ITEM)
+ val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getOrThrow(RegistryKeys.ITEM)
+ var lastWorld: World? = null
+ get() {
+ field = world ?: field
+ return field
+ }
+ private set
}
diff --git a/src/main/kotlin/util/SBData.kt b/src/main/kotlin/util/SBData.kt
index 0b2c404..051d070 100644
--- a/src/main/kotlin/util/SBData.kt
+++ b/src/main/kotlin/util/SBData.kt
@@ -37,7 +37,7 @@ object SBData {
it.serverType.getOrNull()?.name?.uppercase(),
it.mode.getOrNull(),
it.map.getOrNull())
- SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, null))
+ SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, locraw))
profileIdCommandDebounce = TimeMark.now()
}
}
diff --git a/src/main/kotlin/util/SkyblockId.kt b/src/main/kotlin/util/SkyblockId.kt
index 059e746..9c9287b 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 com.mojang.serialization.Codec
import io.github.moulberry.repo.data.NEUIngredient
import io.github.moulberry.repo.data.NEUItem
import io.github.moulberry.repo.data.Rarity
@@ -16,6 +17,9 @@ import net.minecraft.component.type.NbtComponent
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.nbt.NbtCompound
+import net.minecraft.network.RegistryByteBuf
+import net.minecraft.network.codec.PacketCodec
+import net.minecraft.network.codec.PacketCodecs
import net.minecraft.util.Identifier
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.set
@@ -68,6 +72,9 @@ value class SkyblockId(val neuItem: String) {
val NULL: SkyblockId = SkyblockId("null")
val PET_NULL: SkyblockId = SkyblockId("null_pet")
private val illlegalPathRegex = "[^a-z0-9_.-/]".toRegex()
+ val CODEC = Codec.STRING.xmap({ SkyblockId(it) }, { it.neuItem })
+ val PACKET_CODEC: PacketCodec<in RegistryByteBuf, SkyblockId> =
+ PacketCodecs.STRING.xmap({ SkyblockId(it) }, { it.neuItem })
}
}
diff --git a/src/main/kotlin/util/data/IDataHolder.kt b/src/main/kotlin/util/data/IDataHolder.kt
index cc97b58..1e9ba98 100644
--- a/src/main/kotlin/util/data/IDataHolder.kt
+++ b/src/main/kotlin/util/data/IDataHolder.kt
@@ -1,77 +1,71 @@
-
-
package moe.nea.firmament.util.data
import java.util.concurrent.CopyOnWriteArrayList
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
import kotlin.reflect.KClass
-import net.minecraft.client.MinecraftClient
-import net.minecraft.server.command.CommandOutput
import net.minecraft.text.Text
import moe.nea.firmament.Firmament
import moe.nea.firmament.events.ScreenChangeEvent
+import moe.nea.firmament.util.MC
interface IDataHolder<T> {
- companion object {
- internal var badLoads: MutableList<String> = CopyOnWriteArrayList()
- private val allConfigs: MutableMap<KClass<out IDataHolder<*>>, IDataHolder<*>> = mutableMapOf()
- private val dirty: MutableSet<KClass<out IDataHolder<*>>> = mutableSetOf()
+ companion object {
+ internal var badLoads: MutableList<String> = CopyOnWriteArrayList()
+ private val allConfigs: MutableMap<KClass<out IDataHolder<*>>, IDataHolder<*>> = mutableMapOf()
+ private val dirty: MutableSet<KClass<out IDataHolder<*>>> = mutableSetOf()
- internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) {
- allConfigs[kClass] = inst
- }
+ internal fun <T : IDataHolder<K>, K> putDataHolder(kClass: KClass<T>, inst: IDataHolder<K>) {
+ allConfigs[kClass] = inst
+ }
- fun <T : IDataHolder<K>, K> markDirty(kClass: KClass<T>) {
- if (kClass !in allConfigs) {
- Firmament.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'")
- return
- }
- dirty.add(kClass)
- }
+ fun <T : IDataHolder<K>, K> markDirty(kClass: KClass<T>) {
+ if (kClass !in allConfigs) {
+ Firmament.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'")
+ return
+ }
+ dirty.add(kClass)
+ }
- private fun performSaves() {
- val toSave = dirty.toList().also {
- dirty.clear()
- }
- for (it in toSave) {
- val obj = allConfigs[it]
- if (obj == null) {
- Firmament.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'")
- continue
- }
- obj.save()
- }
- }
+ private fun performSaves() {
+ val toSave = dirty.toList().also {
+ dirty.clear()
+ }
+ for (it in toSave) {
+ val obj = allConfigs[it]
+ if (obj == null) {
+ Firmament.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'")
+ continue
+ }
+ obj.save()
+ }
+ }
- private fun warnForResetConfigs(player: CommandOutput) {
- if (badLoads.isNotEmpty()) {
- player.sendMessage(
- Text.literal(
- "The following configs have been reset: ${badLoads.joinToString(", ")}. " +
- "This can be intentional, but probably isn't."
- )
- )
- badLoads.clear()
- }
- }
+ private fun warnForResetConfigs() {
+ if (badLoads.isNotEmpty()) {
+ MC.sendChat(
+ Text.literal(
+ "The following configs have been reset: ${badLoads.joinToString(", ")}. " +
+ "This can be intentional, but probably isn't."
+ )
+ )
+ badLoads.clear()
+ }
+ }
- fun registerEvents() {
- ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event ->
- performSaves()
- val p = MinecraftClient.getInstance().player
- if (p != null) {
- warnForResetConfigs(p)
- }
- }
- ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
- performSaves()
- })
- }
+ fun registerEvents() {
+ ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event ->
+ performSaves()
+ warnForResetConfigs()
+ }
+ ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
+ performSaves()
+ })
+ }
- }
+ }
- val data: T
- fun save()
- fun markDirty()
- fun load()
+ val data: T
+ fun save()
+ fun markDirty()
+ fun load()
}
diff --git a/src/main/kotlin/util/render/DrawContextExt.kt b/src/main/kotlin/util/render/DrawContextExt.kt
index fc38aa6..da0b0b0 100644
--- a/src/main/kotlin/util/render/DrawContextExt.kt
+++ b/src/main/kotlin/util/render/DrawContextExt.kt
@@ -4,12 +4,70 @@ import com.mojang.blaze3d.systems.RenderSystem
import me.shedaniel.math.Color
import org.joml.Matrix4f
import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.render.RenderLayer
+import net.minecraft.client.render.RenderLayer.MultiPhaseParameters
+import net.minecraft.client.render.RenderPhase
+import net.minecraft.client.render.VertexFormat
+import net.minecraft.client.render.VertexFormats
+import net.minecraft.util.Identifier
+import net.minecraft.util.TriState
+import net.minecraft.util.Util
import moe.nea.firmament.util.MC
fun DrawContext.isUntranslatedGuiDrawContext(): Boolean {
return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0
}
+object GuiRenderLayers {
+ val GUI_TEXTURED_NO_DEPTH = Util.memoize<Identifier, RenderLayer> { texture: Identifier ->
+ RenderLayer.of("firmament_gui_textured_no_depth",
+ VertexFormats.POSITION_TEXTURE_COLOR,
+ VertexFormat.DrawMode.QUADS,
+ RenderLayer.CUTOUT_BUFFER_SIZE,
+ MultiPhaseParameters.builder()
+ .texture(RenderPhase.Texture(texture, TriState.FALSE, false))
+ .program(RenderPhase.POSITION_TEXTURE_COLOR_PROGRAM)
+ .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
+ .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
+ .build(false))
+ }
+}
+
+@Deprecated("Use the other drawGuiTexture")
+fun DrawContext.drawGuiTexture(
+ x: Int, y: Int, z: Int, width: Int, height: Int, sprite: Identifier
+) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height)
+
+fun DrawContext.drawGuiTexture(
+ sprite: Identifier,
+ x: Int, y: Int, width: Int, height: Int
+) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height)
+
+fun DrawContext.drawTexture(
+ sprite: Identifier,
+ x: Int,
+ y: Int,
+ u: Float,
+ v: Float,
+ width: Int,
+ height: Int,
+ textureWidth: Int,
+ textureHeight: Int
+) {
+ this.drawTexture(RenderLayer::getGuiTextured,
+ sprite,
+ x,
+ y,
+ u,
+ v,
+ width,
+ height,
+ width,
+ height,
+ textureWidth,
+ textureHeight)
+}
+
fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Color) {
// TODO: push scissors
// TODO: use matrix translations and a different render layer
@@ -18,11 +76,12 @@ fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Colo
return
}
RenderSystem.lineWidth(MC.window.scaleFactor.toFloat())
- val buf = this.vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES)
- buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color)
- .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
- buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color)
- .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
- this.draw()
+ draw { vertexConsumers ->
+ val buf = vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES)
+ buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color)
+ .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
+ buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color)
+ .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
+ }
}
diff --git a/src/main/kotlin/util/render/FacingThePlayerContext.kt b/src/main/kotlin/util/render/FacingThePlayerContext.kt
index eb37e35..daa8da9 100644
--- a/src/main/kotlin/util/render/FacingThePlayerContext.kt
+++ b/src/main/kotlin/util/render/FacingThePlayerContext.kt
@@ -76,13 +76,10 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) {
u1: Float, v1: Float,
u2: Float, v2: Float,
) {
- RenderSystem.setShaderTexture(0, texture)
- RenderSystem.setShader(GameRenderer::getPositionTexColorProgram)
+ val buf = worldContext.vertexConsumers.getBuffer(RenderLayer.getGuiTexturedOverlay(texture))
val hw = width / 2F
val hh = height / 2F
val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix
- val buf = Tessellator.getInstance()
- .begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR)
buf.vertex(matrix4f, -hw, -hh, 0F)
.color(-1)
.texture(u1, v1).next()
@@ -95,7 +92,7 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) {
buf.vertex(matrix4f, +hw, -hh, 0F)
.color(-1)
.texture(u2, v1).next()
- BufferRenderer.drawWithGlobalProgram(buf.end())
+ worldContext.vertexConsumers.draw()
}
}
diff --git a/src/main/kotlin/util/render/FirmamentShaders.kt b/src/main/kotlin/util/render/FirmamentShaders.kt
index 1094bc2..ba67dbb 100644
--- a/src/main/kotlin/util/render/FirmamentShaders.kt
+++ b/src/main/kotlin/util/render/FirmamentShaders.kt
@@ -1,23 +1,30 @@
package moe.nea.firmament.util.render
-import net.minecraft.client.gl.ShaderProgram
+import net.minecraft.client.gl.Defines
+import net.minecraft.client.gl.ShaderProgramKey
import net.minecraft.client.render.RenderPhase
+import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats
+import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
-import moe.nea.firmament.events.RegisterCustomShadersEvent
+import moe.nea.firmament.events.DebugInstantiateEvent
+import moe.nea.firmament.util.MC
object FirmamentShaders {
+ val shaders = mutableListOf<ShaderProgramKey>()
+ private fun shader(name: String, format: VertexFormat, defines: Defines): ShaderProgramKey {
+ val key = ShaderProgramKey(Firmament.identifier(name), format, defines)
+ shaders.add(key)
+ return key
+ }
- private lateinit var _LINES: ShaderProgram
- val LINES = RenderPhase.ShaderProgram({ _LINES })
+ val LINES = RenderPhase.ShaderProgram(shader("core/rendertype_lines", VertexFormats.LINES, Defines.EMPTY))
- @Subscribe
- fun registerCustomShaders(event: RegisterCustomShadersEvent) {
- event.register(
- "firmament_rendertype_lines",
- VertexFormats.LINES,
- { _LINES = it },
- )
- }
+ @Subscribe
+ fun debugLoad(event: DebugInstantiateEvent) {
+ shaders.forEach {
+ MC.instance.shaderLoader.getOrCreateProgram(it)
+ }
+ }
}
diff --git a/src/main/kotlin/util/render/RenderCircleProgress.kt b/src/main/kotlin/util/render/RenderCircleProgress.kt
index a2f42b5..9cc383c 100644
--- a/src/main/kotlin/util/render/RenderCircleProgress.kt
+++ b/src/main/kotlin/util/render/RenderCircleProgress.kt
@@ -1,4 +1,3 @@
-
package moe.nea.firmament.util.render
import com.mojang.blaze3d.systems.RenderSystem
@@ -9,7 +8,8 @@ import kotlin.math.atan2
import kotlin.math.tan
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.render.BufferRenderer
-import net.minecraft.client.render.GameRenderer
+import net.minecraft.client.render.RenderLayer
+import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexFormat.DrawMode
import net.minecraft.client.render.VertexFormats
@@ -17,79 +17,77 @@ import net.minecraft.util.Identifier
object RenderCircleProgress {
- fun renderCircle(
- drawContext: DrawContext,
- texture: Identifier,
- progress: Float,
- u1: Float,
- u2: Float,
- v1: Float,
- v2: Float,
- ) {
- RenderSystem.setShaderTexture(0, texture)
- RenderSystem.setShader(GameRenderer::getPositionTexColorProgram)
- RenderSystem.enableBlend()
- val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix
- val bufferBuilder = Tessellator.getInstance().begin(DrawMode.TRIANGLES, VertexFormats.POSITION_TEXTURE_COLOR)
-
- val corners = listOf(
- Vector2f(0F, -1F),
- Vector2f(1F, -1F),
- Vector2f(1F, 0F),
- Vector2f(1F, 1F),
- Vector2f(0F, 1F),
- Vector2f(-1F, 1F),
- Vector2f(-1F, 0F),
- Vector2f(-1F, -1F),
- )
+ fun renderCircle(
+ drawContext: DrawContext,
+ texture: Identifier,
+ progress: Float,
+ u1: Float,
+ u2: Float,
+ v1: Float,
+ v2: Float,
+ ) {
+ RenderSystem.enableBlend()
+ drawContext.draw {
+ val bufferBuilder = it.getBuffer(RenderLayer.getGuiTexturedOverlay(texture))
+ val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix
- for (i in (0 until 8)) {
- if (progress < i / 8F) {
- break
- }
- val second = corners[(i + 1) % 8]
- val first = corners[i]
- if (progress <= (i + 1) / 8F) {
- val internalProgress = 1 - (progress - i / 8F) * 8F
- val angle = lerpAngle(
- atan2(second.y, second.x),
- atan2(first.y, first.x),
- internalProgress
- )
- if (angle < tau / 8 || angle >= tau * 7 / 8) {
- second.set(1F, tan(angle))
- } else if (angle < tau * 3 / 8) {
- second.set(1 / tan(angle), 1F)
- } else if (angle < tau * 5 / 8) {
- second.set(-1F, -tan(angle))
- } else {
- second.set(-1 / tan(angle), -1F)
- }
- }
+ val corners = listOf(
+ Vector2f(0F, -1F),
+ Vector2f(1F, -1F),
+ Vector2f(1F, 0F),
+ Vector2f(1F, 1F),
+ Vector2f(0F, 1F),
+ Vector2f(-1F, 1F),
+ Vector2f(-1F, 0F),
+ Vector2f(-1F, -1F),
+ )
- fun ilerp(f: Float): Float =
- ilerp(-1f, 1f, f)
+ for (i in (0 until 8)) {
+ if (progress < i / 8F) {
+ break
+ }
+ val second = corners[(i + 1) % 8]
+ val first = corners[i]
+ if (progress <= (i + 1) / 8F) {
+ val internalProgress = 1 - (progress - i / 8F) * 8F
+ val angle = lerpAngle(
+ atan2(second.y, second.x),
+ atan2(first.y, first.x),
+ internalProgress
+ )
+ if (angle < tau / 8 || angle >= tau * 7 / 8) {
+ second.set(1F, tan(angle))
+ } else if (angle < tau * 3 / 8) {
+ second.set(1 / tan(angle), 1F)
+ } else if (angle < tau * 5 / 8) {
+ second.set(-1F, -tan(angle))
+ } else {
+ second.set(-1 / tan(angle), -1F)
+ }
+ }
- bufferBuilder
- .vertex(matrix, second.x, second.y, 0F)
- .texture(lerp(u1, u2, ilerp(second.x)), lerp(v1, v2, ilerp(second.y)))
- .color(-1)
- .next()
- bufferBuilder
- .vertex(matrix, first.x, first.y, 0F)
- .texture(lerp(u1, u2, ilerp(first.x)), lerp(v1, v2, ilerp(first.y)))
- .color(-1)
- .next()
- bufferBuilder
- .vertex(matrix, 0F, 0F, 0F)
- .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F)))
- .color(-1)
- .next()
- }
- BufferRenderer.drawWithGlobalProgram(bufferBuilder.end())
- RenderSystem.disableBlend()
- }
+ fun ilerp(f: Float): Float =
+ ilerp(-1f, 1f, f)
+ bufferBuilder
+ .vertex(matrix, second.x, second.y, 0F)
+ .texture(lerp(u1, u2, ilerp(second.x)), lerp(v1, v2, ilerp(second.y)))
+ .color(-1)
+ .next()
+ bufferBuilder
+ .vertex(matrix, first.x, first.y, 0F)
+ .texture(lerp(u1, u2, ilerp(first.x)), lerp(v1, v2, ilerp(first.y)))
+ .color(-1)
+ .next()
+ bufferBuilder
+ .vertex(matrix, 0F, 0F, 0F)
+ .texture(lerp(u1, u2, ilerp(0F)), lerp(v1, v2, ilerp(0F)))
+ .color(-1)
+ .next()
+ }
+ }
+ RenderSystem.disableBlend()
+ }
}
diff --git a/src/main/kotlin/util/render/RenderInWorldContext.kt b/src/main/kotlin/util/render/RenderInWorldContext.kt
index b61b9aa..bb58200 100644
--- a/src/main/kotlin/util/render/RenderInWorldContext.kt
+++ b/src/main/kotlin/util/render/RenderInWorldContext.kt
@@ -1,5 +1,3 @@
-
-
package moe.nea.firmament.util.render
import com.mojang.blaze3d.systems.RenderSystem
@@ -8,14 +6,12 @@ import java.lang.Math.pow
import org.joml.Matrix4f
import org.joml.Vector3f
import net.minecraft.client.gl.VertexBuffer
-import net.minecraft.client.render.BufferBuilder
-import net.minecraft.client.render.BufferRenderer
import net.minecraft.client.render.Camera
-import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.RenderTickCounter
import net.minecraft.client.render.Tessellator
+import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats
@@ -31,273 +27,287 @@ import moe.nea.firmament.util.MC
@RenderContextDSL
class RenderInWorldContext private constructor(
- private val tesselator: Tessellator,
- val matrixStack: MatrixStack,
- private val camera: Camera,
- private val tickCounter: RenderTickCounter,
- val vertexConsumers: VertexConsumerProvider.Immediate,
+ private val tesselator: Tessellator,
+ val matrixStack: MatrixStack,
+ private val camera: Camera,
+ private val tickCounter: RenderTickCounter,
+ val vertexConsumers: VertexConsumerProvider.Immediate,
) {
- object RenderLayers {
- val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris",
- VertexFormats.POSITION_COLOR,
- VertexFormat.DrawMode.TRIANGLES,
- RenderLayer.DEFAULT_BUFFER_SIZE,
- false, true,
- RenderLayer.MultiPhaseParameters.builder()
- .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
- .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
- .program(RenderPhase.COLOR_PROGRAM)
- .build(false))
- val LINES = RenderLayer.of("firmament_rendertype_lines",
- VertexFormats.LINES,
- VertexFormat.DrawMode.LINES,
- RenderLayer.DEFAULT_BUFFER_SIZE,
- false, false, // do we need translucent? i dont think so
- RenderLayer.MultiPhaseParameters.builder()
- .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
- .program(FirmamentShaders.LINES)
- .build(false)
- )
- }
-
- fun color(color: me.shedaniel.math.Color) {
- color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f)
- }
-
- fun color(red: Float, green: Float, blue: Float, alpha: Float) {
- RenderSystem.setShaderColor(red, green, blue, alpha)
- }
-
- fun block(blockPos: BlockPos) {
- matrixStack.push()
- matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat())
- buildCube(matrixStack.peek().positionMatrix, tesselator)
- matrixStack.pop()
- }
-
- enum class VerticalAlign {
- TOP, BOTTOM, CENTER;
-
- fun align(index: Int, count: Int): Float {
- return when (this) {
- CENTER -> (index - count / 2F) * (1 + MC.font.fontHeight.toFloat())
- BOTTOM -> (index - count) * (1 + MC.font.fontHeight.toFloat())
- TOP -> (index) * (1 + MC.font.fontHeight.toFloat())
- }
- }
- }
-
- fun waypoint(position: BlockPos, vararg label: Text) {
- text(
- position.toCenterPos(),
- *label,
- Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}"),
- background = 0xAA202020.toInt()
- )
- }
-
- fun withFacingThePlayer(position: Vec3d, block: FacingThePlayerContext.() -> Unit) {
- matrixStack.push()
- matrixStack.translate(position.x, position.y, position.z)
- val actualCameraDistance = position.distanceTo(camera.pos)
- val distanceToMoveTowardsCamera = if (actualCameraDistance < 10) 0.0 else -(actualCameraDistance - 10.0)
- val vec = position.subtract(camera.pos).multiply(distanceToMoveTowardsCamera / actualCameraDistance)
- matrixStack.translate(vec.x, vec.y, vec.z)
- matrixStack.multiply(camera.rotation)
- matrixStack.scale(0.025F, -0.025F, 1F)
-
- FacingThePlayerContext(this).run(block)
-
- matrixStack.pop()
- vertexConsumers.drawCurrentLayer()
- }
-
- fun sprite(position: Vec3d, sprite: Sprite, width: Int, height: Int) {
- texture(
- position, sprite.atlasId, width, height, sprite.minU, sprite.minV, sprite.maxU, sprite.maxV
- )
- }
-
- fun texture(
- position: Vec3d, texture: Identifier, width: Int, height: Int,
- u1: Float, v1: Float,
- u2: Float, v2: Float,
- ) {
- withFacingThePlayer(position) {
- texture(texture, width, height, u1, v1, u2, v2)
- }
- }
-
- fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER, background: Int = 0x70808080) {
- withFacingThePlayer(position) {
- text(*texts, verticalAlign = verticalAlign, background = background)
- }
- }
-
- fun tinyBlock(vec3d: Vec3d, size: Float) {
- RenderSystem.setShader(GameRenderer::getPositionColorProgram)
- matrixStack.push()
- matrixStack.translate(vec3d.x, vec3d.y, vec3d.z)
- matrixStack.scale(size, size, size)
- matrixStack.translate(-.5, -.5, -.5)
- buildCube(matrixStack.peek().positionMatrix, tesselator)
- matrixStack.pop()
- }
-
- fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) {
- RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram)
- matrixStack.push()
- RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat())
- matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat())
- buildWireFrameCube(matrixStack.peek(), tesselator)
- matrixStack.pop()
- }
-
- fun line(vararg points: Vec3d, lineWidth: Float = 10F) {
- line(points.toList(), lineWidth)
- }
-
- fun tracer(toWhere: Vec3d, lineWidth: Float = 3f) {
- val cameraForward = Vector3f(0f, 0f, -1f).rotate(camera.rotation)
- line(camera.pos.add(Vec3d(cameraForward)), toWhere, lineWidth = lineWidth)
- }
-
- fun line(points: List<Vec3d>, lineWidth: Float = 10F) {
- RenderSystem.lineWidth(lineWidth)
- val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
-
- val matrix = matrixStack.peek()
- var lastNormal: Vector3f? = null
- points.zipWithNext().forEach { (a, b) ->
- val normal = Vector3f(b.x.toFloat(), b.y.toFloat(), b.z.toFloat())
- .sub(a.x.toFloat(), a.y.toFloat(), a.z.toFloat())
- .normalize()
- val lastNormal0 = lastNormal ?: normal
- lastNormal = normal
- buffer.vertex(matrix.positionMatrix, a.x.toFloat(), a.y.toFloat(), a.z.toFloat())
- .color(-1)
- .normal(matrix, lastNormal0.x, lastNormal0.y, lastNormal0.z)
- .next()
- buffer.vertex(matrix.positionMatrix, b.x.toFloat(), b.y.toFloat(), b.z.toFloat())
- .color(-1)
- .normal(matrix, normal.x, normal.y, normal.z)
- .next()
- }
-
- RenderLayers.LINES.draw(buffer.end())
- }
-
- companion object {
- private fun doLine(
- matrix: MatrixStack.Entry,
- buf: BufferBuilder,
- i: Float,
- j: Float,
- k: Float,
- x: Float,
- y: Float,
- z: Float
- ) {
- val normal = Vector3f(x, y, z)
- .sub(i, j, k)
- .normalize()
- buf.vertex(matrix.positionMatrix, i, j, k)
- .normal(matrix, normal.x, normal.y, normal.z)
- .color(-1)
- .next()
- buf.vertex(matrix.positionMatrix, x, y, z)
- .normal(matrix, normal.x, normal.y, normal.z)
- .color(-1)
- .next()
- }
-
-
- private fun buildWireFrameCube(matrix: MatrixStack.Entry, tessellator: Tessellator) {
- val buf = tessellator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
-
- for (i in 0..1) {
- for (j in 0..1) {
- val i = i.toFloat()
- val j = j.toFloat()
- doLine(matrix, buf, 0F, i, j, 1F, i, j)
- doLine(matrix, buf, i, 0F, j, i, 1F, j)
- doLine(matrix, buf, i, j, 0F, i, j, 1F)
- }
- }
- BufferRenderer.drawWithGlobalProgram(buf.end())
- }
-
- private fun buildCube(matrix: Matrix4f, tessellator: Tessellator) {
- val buf = tessellator.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR)
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
- buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
- RenderLayers.TRANSLUCENT_TRIS.draw(buf.end())
- }
-
-
- fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) {
- RenderSystem.disableDepthTest()
- RenderSystem.enableBlend()
- RenderSystem.defaultBlendFunc()
- RenderSystem.disableCull()
-
- event.matrices.push()
- event.matrices.translate(-event.camera.pos.x, -event.camera.pos.y, -event.camera.pos.z)
-
- val ctx = RenderInWorldContext(
- RenderSystem.renderThreadTesselator(),
- event.matrices,
- event.camera,
- event.tickCounter,
- event.vertexConsumers
- )
-
- block(ctx)
-
- event.matrices.pop()
-
- RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
- VertexBuffer.unbind()
- RenderSystem.enableDepthTest()
- RenderSystem.enableCull()
- RenderSystem.disableBlend()
- }
- }
+ object RenderLayers {
+ val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris",
+ VertexFormats.POSITION_COLOR,
+ VertexFormat.DrawMode.TRIANGLES,
+ RenderLayer.CUTOUT_BUFFER_SIZE,
+ false, true,
+ RenderLayer.MultiPhaseParameters.builder()
+ .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
+ .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
+ .program(RenderPhase.POSITION_COLOR_PROGRAM)
+ .build(false))
+ val LINES = RenderLayer.of("firmament_rendertype_lines",
+ VertexFormats.LINES,
+ VertexFormat.DrawMode.LINES,
+ RenderLayer.CUTOUT_BUFFER_SIZE,
+ false, false, // do we need translucent? i dont think so
+ RenderLayer.MultiPhaseParameters.builder()
+ .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
+ .program(FirmamentShaders.LINES)
+ .build(false)
+ )
+ val COLORED_QUADS = RenderLayer.of(
+ "firmament_quads",
+ VertexFormats.POSITION_COLOR,
+ VertexFormat.DrawMode.QUADS,
+ RenderLayer.CUTOUT_BUFFER_SIZE,
+ false, true,
+ RenderLayer.MultiPhaseParameters.builder()
+ .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
+ .program(RenderPhase.POSITION_COLOR_PROGRAM)
+ .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
+ .build(false)
+ )
+ }
+
+ @Deprecated("stateful color management is no longer a thing")
+ fun color(color: me.shedaniel.math.Color) {
+ color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f)
+ }
+
+ @Deprecated("stateful color management is no longer a thing")
+ fun color(red: Float, green: Float, blue: Float, alpha: Float) {
+ RenderSystem.setShaderColor(red, green, blue, alpha)
+ }
+
+ fun block(blockPos: BlockPos, color: Int) {
+ matrixStack.push()
+ matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat())
+ buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayers.COLORED_QUADS), color)
+ matrixStack.pop()
+ }
+
+ enum class VerticalAlign {
+ TOP, BOTTOM, CENTER;
+
+ fun align(index: Int, count: Int): Float {
+ return when (this) {
+ CENTER -> (index - count / 2F) * (1 + MC.font.fontHeight.toFloat())
+ BOTTOM -> (index - count) * (1 + MC.font.fontHeight.toFloat())
+ TOP -> (index) * (1 + MC.font.fontHeight.toFloat())
+ }
+ }
+ }
+
+ fun waypoint(position: BlockPos, vararg label: Text) {
+ text(
+ position.toCenterPos(),
+ *label,
+ Text.literal("§e${FirmFormatters.formatDistance(MC.player?.pos?.distanceTo(position.toCenterPos()) ?: 42069.0)}"),
+ background = 0xAA202020.toInt()
+ )
+ }
+
+ fun withFacingThePlayer(position: Vec3d, block: FacingThePlayerContext.() -> Unit) {
+ matrixStack.push()
+ matrixStack.translate(position.x, position.y, position.z)
+ val actualCameraDistance = position.distanceTo(camera.pos)
+ val distanceToMoveTowardsCamera = if (actualCameraDistance < 10) 0.0 else -(actualCameraDistance - 10.0)
+ val vec = position.subtract(camera.pos).multiply(distanceToMoveTowardsCamera / actualCameraDistance)
+ matrixStack.translate(vec.x, vec.y, vec.z)
+ matrixStack.multiply(camera.rotation)
+ matrixStack.scale(0.025F, -0.025F, 1F)
+
+ FacingThePlayerContext(this).run(block)
+
+ matrixStack.pop()
+ vertexConsumers.drawCurrentLayer()
+ }
+
+ fun sprite(position: Vec3d, sprite: Sprite, width: Int, height: Int) {
+ texture(
+ position, sprite.atlasId, width, height, sprite.minU, sprite.minV, sprite.maxU, sprite.maxV
+ )
+ }
+
+ fun texture(
+ position: Vec3d, texture: Identifier, width: Int, height: Int,
+ u1: Float, v1: Float,
+ u2: Float, v2: Float,
+ ) {
+ withFacingThePlayer(position) {
+ texture(texture, width, height, u1, v1, u2, v2)
+ }
+ }
+
+ fun text(
+ position: Vec3d,
+ vararg texts: Text,
+ verticalAlign: VerticalAlign = VerticalAlign.CENTER,
+ background: Int = 0x70808080
+ ) {
+ withFacingThePlayer(position) {
+ text(*texts, verticalAlign = verticalAlign, background = background)
+ }
+ }
+
+ fun tinyBlock(vec3d: Vec3d, size: Float, color: Int) {
+ matrixStack.push()
+ matrixStack.translate(vec3d.x, vec3d.y, vec3d.z)
+ matrixStack.scale(size, size, size)
+ matrixStack.translate(-.5, -.5, -.5)
+ buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayers.COLORED_QUADS), color)
+ matrixStack.pop()
+ vertexConsumers.draw()
+ }
+
+ fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) {
+ val buf = vertexConsumers.getBuffer(RenderLayer.LINES)
+ matrixStack.push()
+ // TODO: this does not render through blocks (or water layers) anymore
+ RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat())
+ matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat())
+ buildWireFrameCube(matrixStack.peek(), buf)
+ matrixStack.pop()
+ vertexConsumers.draw()
+ }
+
+ fun line(vararg points: Vec3d, lineWidth: Float = 10F) {
+ line(points.toList(), lineWidth)
+ }
+
+ fun tracer(toWhere: Vec3d, lineWidth: Float = 3f) {
+ val cameraForward = Vector3f(0f, 0f, -1f).rotate(camera.rotation)
+ line(camera.pos.add(Vec3d(cameraForward)), toWhere, lineWidth = lineWidth)
+ }
+
+ fun line(points: List<Vec3d>, lineWidth: Float = 10F) {
+ RenderSystem.lineWidth(lineWidth)
+ // TODO: replace with renderlayers
+ val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
+
+ val matrix = matrixStack.peek()
+ var lastNormal: Vector3f? = null
+ points.zipWithNext().forEach { (a, b) ->
+ val normal = Vector3f(b.x.toFloat(), b.y.toFloat(), b.z.toFloat())
+ .sub(a.x.toFloat(), a.y.toFloat(), a.z.toFloat())
+ .normalize()
+ val lastNormal0 = lastNormal ?: normal
+ lastNormal = normal
+ buffer.vertex(matrix.positionMatrix, a.x.toFloat(), a.y.toFloat(), a.z.toFloat())
+ .color(-1)
+ .normal(matrix, lastNormal0.x, lastNormal0.y, lastNormal0.z)
+ .next()
+ buffer.vertex(matrix.positionMatrix, b.x.toFloat(), b.y.toFloat(), b.z.toFloat())
+ .color(-1)
+ .normal(matrix, normal.x, normal.y, normal.z)
+ .next()
+ }
+
+ RenderLayers.LINES.draw(buffer.end())
+ }
+ // TODO: put the favourite icons in front of items again
+
+ companion object {
+ private fun doLine(
+ matrix: MatrixStack.Entry,
+ buf: VertexConsumer,
+ i: Float,
+ j: Float,
+ k: Float,
+ x: Float,
+ y: Float,
+ z: Float
+ ) {
+ val normal = Vector3f(x, y, z)
+ .sub(i, j, k)
+ .normalize()
+ buf.vertex(matrix.positionMatrix, i, j, k)
+ .normal(matrix, normal.x, normal.y, normal.z)
+ .color(-1)
+ .next()
+ buf.vertex(matrix.positionMatrix, x, y, z)
+ .normal(matrix, normal.x, normal.y, normal.z)
+ .color(-1)
+ .next()
+ }
+
+
+ private fun buildWireFrameCube(matrix: MatrixStack.Entry, buf: VertexConsumer) {
+ for (i in 0..1) {
+ for (j in 0..1) {
+ val i = i.toFloat()
+ val j = j.toFloat()
+ doLine(matrix, buf, 0F, i, j, 1F, i, j)
+ doLine(matrix, buf, i, 0F, j, i, 1F, j)
+ doLine(matrix, buf, i, j, 0F, i, j, 1F)
+ }
+ }
+ }
+
+ private fun buildCube(matrix: Matrix4f, buf: VertexConsumer, color: Int) {
+ // Y-
+ buf.vertex(matrix, 0F, 0F, 0F).color(color)
+ buf.vertex(matrix, 0F, 0F, 1F).color(color)
+ buf.vertex(matrix, 1F, 0F, 1F).color(color)
+ buf.vertex(matrix, 1F, 0F, 0F).color(color)
+ // Y+
+ buf.vertex(matrix, 0F, 1F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 1F).color(color)
+ buf.vertex(matrix, 0F, 1F, 1F).color(color)
+ // X-
+ buf.vertex(matrix, 0F, 0F, 0F).color(color)
+ buf.vertex(matrix, 0F, 0F, 1F).color(color)
+ buf.vertex(matrix, 0F, 1F, 1F).color(color)
+ buf.vertex(matrix, 0F, 1F, 0F).color(color)
+ // X+
+ buf.vertex(matrix, 1F, 0F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 1F).color(color)
+ buf.vertex(matrix, 1F, 0F, 1F).color(color)
+ // Z-
+ buf.vertex(matrix, 0F, 0F, 0F).color(color)
+ buf.vertex(matrix, 1F, 0F, 0F).color(color)
+ buf.vertex(matrix, 1F, 1F, 0F).color(color)
+ buf.vertex(matrix, 0F, 1F, 0F).color(color)
+ // Z+
+ buf.vertex(matrix, 0F, 0F, 1F).color(color)
+ buf.vertex(matrix, 0F, 1F, 1F).color(color)
+ buf.vertex(matrix, 1F, 1F, 1F).color(color)
+ buf.vertex(matrix, 1F, 0F, 1F).color(color)
+ }
+
+
+ fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) {
+ // TODO: there should be *no more global state*. the only thing we should be doing is render layers. that includes settings like culling, blending, shader color, and depth testing
+ // For now i will let these functions remain, but this needs to go before i do a full (non-beta) release
+ RenderSystem.disableDepthTest()
+ RenderSystem.enableBlend()
+ RenderSystem.defaultBlendFunc()
+ RenderSystem.disableCull()
+
+ event.matrices.push()
+ event.matrices.translate(-event.camera.pos.x, -event.camera.pos.y, -event.camera.pos.z)
+
+ val ctx = RenderInWorldContext(
+ RenderSystem.renderThreadTesselator(),
+ event.matrices,
+ event.camera,
+ event.tickCounter,
+ event.vertexConsumers
+ )
+
+ block(ctx)
+
+ event.matrices.pop()
+ event.vertexConsumers.draw()
+ RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
+ VertexBuffer.unbind()
+ RenderSystem.enableDepthTest()
+ RenderSystem.enableCull()
+ RenderSystem.disableBlend()
+ }
+ }
}
diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh b/src/main/resources/assets/firmament/shaders/core/rendertype_lines.fsh
index 057f31f..057f31f 100644
--- a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.fsh
+++ b/src/main/resources/assets/firmament/shaders/core/rendertype_lines.fsh
diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json b/src/main/resources/assets/firmament/shaders/core/rendertype_lines.json
index 0828480..e4537ca 100644
--- a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.json
+++ b/src/main/resources/assets/firmament/shaders/core/rendertype_lines.json
@@ -1,6 +1,6 @@
{
- "vertex": "firmament_rendertype_lines",
- "fragment": "firmament_rendertype_lines",
+ "vertex": "firmament:core/rendertype_lines",
+ "fragment": "firmament:core/rendertype_lines",
"samplers": [
],
"uniforms": [
@@ -8,7 +8,7 @@
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
{ "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] },
{ "name": "LineWidth", "type": "float", "count": 1, "values": [ 1.0 ] },
- { "name": "ScreenSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
+ { "name": "ScreenSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
{ "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] },
{ "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] },
{ "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] },
diff --git a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh b/src/main/resources/assets/firmament/shaders/core/rendertype_lines.vsh
index b2d0f99..b2d0f99 100644
--- a/src/main/resources/assets/minecraft/shaders/core/firmament_rendertype_lines.vsh
+++ b/src/main/resources/assets/firmament/shaders/core/rendertype_lines.vsh
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index 9997018..9b00adf 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -33,6 +33,9 @@
"rei_client": [
"moe.nea.firmament.compat.rei.FirmamentReiPlugin"
],
+ "rei_common": [
+ "moe.nea.firmament.compat.rei.FirmamentReiCommonPlugin"
+ ],
"modmenu": [
"moe.nea.firmament.compat.modmenu.FirmamentModMenuPlugin"
],
diff --git a/src/main/resources/firmament.accesswidener b/src/main/resources/firmament.accesswidener
index 60b31e3..f1a897b 100644
--- a/src/main/resources/firmament.accesswidener
+++ b/src/main/resources/firmament.accesswidener
@@ -5,6 +5,7 @@ accessible class net/minecraft/client/font/TextRenderer$Drawer
accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARATOR Ljava/util/Comparator;
accessible field net/minecraft/client/render/item/HeldItemRenderer itemRenderer Lnet/minecraft/client/render/item/ItemRenderer;
+accessible field net/minecraft/client/render/item/ItemModels missingModelSupplier Ljava/util/function/Supplier;
accessible class net/minecraft/client/render/model/json/ModelOverride$Deserializer
accessible class net/minecraft/client/render/model/json/ModelOverrideList$BakedOverride
@@ -14,7 +15,7 @@ accessible field net/minecraft/entity/passive/AbstractHorseEntity items Lnet/min
accessible field net/minecraft/entity/passive/AbstractHorseEntity SADDLED_FLAG I
accessible field net/minecraft/entity/passive/AbstractHorseEntity HORSE_FLAGS Lnet/minecraft/entity/data/TrackedData;
accessible method net/minecraft/resource/NamespaceResourceManager loadMetadata (Lnet/minecraft/resource/InputSupplier;)Lnet/minecraft/resource/metadata/ResourceMetadata;
-accessible method net/minecraft/client/gui/DrawContext drawTexturedQuad (Lnet/minecraft/util/Identifier;IIIIIFFFFFFFF)V
+accessible method net/minecraft/client/gui/DrawContext drawTexturedQuad (Ljava/util/function/Function;Lnet/minecraft/util/Identifier;IIIIFFFFI)V
mutable field net/minecraft/screen/slot/Slot x I
mutable field net/minecraft/screen/slot/Slot y I
@@ -27,3 +28,4 @@ accessible method net/minecraft/registry/entry/RegistryEntry$Reference setRegist
accessible method net/minecraft/entity/LivingEntity getHitbox ()Lnet/minecraft/util/math/Box;
accessible method net/minecraft/registry/entry/RegistryEntryList$Named <init> (Lnet/minecraft/registry/entry/RegistryEntryOwner;Lnet/minecraft/registry/tag/TagKey;)V
accessible method net/minecraft/registry/entry/RegistryEntry$Reference setValue (Ljava/lang/Object;)V
+accessible field net/minecraft/client/render/model/WrapperBakedModel wrapped Lnet/minecraft/client/render/model/BakedModel;
diff --git a/src/main/resources/firmament.mixins.json b/src/main/resources/firmament.mixins.json
index dbb8290..d78d124 100644
--- a/src/main/resources/firmament.mixins.json
+++ b/src/main/resources/firmament.mixins.json
@@ -1,7 +1,10 @@
{
- "required": true,
- "plugin": "moe.nea.firmament.init.MixinPlugin",
- "package": "moe.nea.firmament.mixins",
- "compatibilityLevel": "JAVA_21",
- "refmap": "Firmament-refmap.json"
+ "required": true,
+ "plugin": "moe.nea.firmament.init.MixinPlugin",
+ "package": "moe.nea.firmament.mixins",
+ "compatibilityLevel": "JAVA_21",
+ "refmap": "Firmament-refmap.json",
+ "injectors": {
+ "defaultRequire": 1
+ }
}