diff options
Diffstat (limited to 'src/main/kotlin')
37 files changed, 1066 insertions, 1169 deletions
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..d5c08f4 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/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/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/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..5507752 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.drawGuiTexture import moe.nea.firmament.util.render.drawLine import moe.nea.firmament.util.skyblockUUID import moe.nea.firmament.util.unformattedString @@ -332,21 +333,19 @@ object SlotLocking : FirmamentFeature { val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf()) if (isSlotLocked || isUUIDLocked) { RenderSystem.disableDepthTest() - it.context.drawSprite( + it.context.drawGuiTexture( it.slot.x, it.slot.y, 0, 16, 16, - MC.guiAtlasManager.getSprite( - when { - isSlotLocked -> - (Identifier.of("firmament:slot_locked")) - - isUUIDLocked -> - (Identifier.of("firmament:uuid_locked")) - - else -> - error("unreachable") - } - ) + when { + isSlotLocked -> + (Identifier.of("firmament:slot_locked")) + + isUUIDLocked -> + (Identifier.of("firmament:uuid_locked")) + + else -> + error("unreachable") + } ) 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/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/world/Waypoints.kt b/src/main/kotlin/features/world/Waypoints.kt index d535b4e..72b3c7e 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,279 @@ 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 { + color(0f, 0.3f, 0.7f, 0.5f) + block(it.value) + color(1f, 1f, 1f, 1f) + if (TConfig.showIndex) + withFacingThePlayer(it.value.toCenterPos()) { + text(Text.literal(it.index.toString())) + } + } + } else { + orderedIndex %= waypoints.size + val firstColor = Color.ofRGBA(0, 200, 40, 180) + color(firstColor) + tracer(waypoints[orderedIndex].toCenterPos(), lineWidth = 3f) + waypoints.withIndex().toList() + .wrappingWindow(orderedIndex, 3) + .zip( + listOf( + firstColor, + Color.ofRGBA(180, 200, 40, 150), + Color.ofRGBA(180, 80, 20, 140), + ) + ) + .reversed() + .forEach { (waypoint, col) -> + val (index, pos) = waypoint + color(col) + block(pos) + color(1f, 1f, 1f, 1f) + if (TConfig.showIndex) + withFacingThePlayer(pos.toCenterPos()) { + text(Text.literal(index.toString())) + } + } + } + } + } - @Subscribe - fun onTick(event: TickEvent) { - if (waypoints.isEmpty() || !ordered) return - orderedIndex %= waypoints.size - val p = MC.player?.pos ?: return - if (TConfig.skipToNearest) { - orderedIndex = - (waypoints.withIndex().minBy { it.value.getSquaredDistance(p) }.index + 1) % waypoints.size - } else { - if (waypoints[orderedIndex].isWithinDistance(p, 3.0)) { - orderedIndex = (orderedIndex + 1) % waypoints.size - } - } - } + @Subscribe + fun 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) { + color(1f, 1f, 0f, 1f) + temporaryPlayerWaypointList.forEach { (player, waypoint) -> + block(waypoint.pos) + } + color(1f, 1f, 1f, 1f) + temporaryPlayerWaypointList.forEach { (player, waypoint) -> + val skin = + MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } + ?.skinTextures + ?.texture + withFacingThePlayer(waypoint.pos.toCenterPos()) { + waypoint(waypoint.pos, Text.stringifiedTranslatable("firmament.waypoint.temporary", player)) + if (skin != null) { + matrixStack.translate(0F, -20F, 0F) + // Head front + texture( + skin, 16, 16, + 1 / 8f, 1 / 8f, + 2 / 8f, 2 / 8f, + ) + // Head overlay + texture( + skin, 16, 16, + 5 / 8f, 1 / 8f, + 6 / 8f, 2 / 8f, + ) + } + } + } + } + } - @Subscribe - fun onWorldReady(event: WorldReadyEvent) { - temporaryPlayerWaypointList.clear() - } + @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..ebff1a0 100644 --- a/src/main/kotlin/gui/entity/EntityRenderer.kt +++ b/src/main/kotlin/gui/entity/EntityRenderer.kt @@ -13,6 +13,7 @@ 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 moe.nea.firmament.util.MC import moe.nea.firmament.util.assertNotNullOr @@ -23,7 +24,7 @@ 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)!! } + return { entityType.create(fakeWorld, SpawnReason.LOAD)!! } } val entityIds: Map<String, () -> LivingEntity> = mapOf( diff --git a/src/main/kotlin/gui/entity/FakeWorld.kt b/src/main/kotlin/gui/entity/FakeWorld.kt index f354d5a..c17f2ad 100644 --- a/src/main/kotlin/gui/entity/FakeWorld.kt +++ b/src/main/kotlin/gui/entity/FakeWorld.kt @@ -1,35 +1,28 @@ - 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.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.entry.RegistryEntry -import net.minecraft.registry.entry.RegistryEntryInfo -import net.minecraft.registry.entry.RegistryEntryList -import net.minecraft.registry.entry.RegistryEntryOwner -import net.minecraft.registry.tag.TagKey import net.minecraft.resource.featuretoggle.FeatureFlags import net.minecraft.resource.featuretoggle.FeatureSet import net.minecraft.scoreboard.Scoreboard @@ -43,11 +36,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 +49,283 @@ 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()]) - } - } -} - 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>>) } - } - } + 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, + registries.getOrThrow(RegistryKeys.DIMENSION_TYPE).getEntry( + Identifier.of("minecraft", "overworld") + ).get(), + 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/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..e5103fc 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()) // TODO: check https://hackmd.io/@shedaniel/rei17_primer and source to see if this still resyncs ) != null } @@ -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/util/MC.kt b/src/main/kotlin/util/MC.kt index fc42be9..27b9457 100644 --- a/src/main/kotlin/util/MC.kt +++ b/src/main/kotlin/util/MC.kt @@ -92,7 +92,7 @@ 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) } 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..14ee8e7 100644 --- a/src/main/kotlin/util/render/DrawContextExt.kt +++ b/src/main/kotlin/util/render/DrawContextExt.kt @@ -4,12 +4,49 @@ 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.util.Identifier import moe.nea.firmament.util.MC fun DrawContext.isUntranslatedGuiDrawContext(): Boolean { return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0 } +@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 +55,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..5147088 100644 --- a/src/main/kotlin/util/render/FirmamentShaders.kt +++ b/src/main/kotlin/util/render/FirmamentShaders.kt @@ -1,23 +1,16 @@ 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.VertexFormats -import moe.nea.firmament.annotations.Subscribe -import moe.nea.firmament.events.RegisterCustomShadersEvent +import moe.nea.firmament.Firmament object FirmamentShaders { - private lateinit var _LINES: ShaderProgram - val LINES = RenderPhase.ShaderProgram({ _LINES }) + val _LINES: ShaderProgramKey = + ShaderProgramKey(Firmament.identifier("rendertype_lines"), VertexFormats.LINES, Defines.EMPTY) + val LINES = RenderPhase.ShaderProgram(_LINES) - @Subscribe - fun registerCustomShaders(event: RegisterCustomShadersEvent) { - event.register( - "firmament_rendertype_lines", - VertexFormats.LINES, - { _LINES = 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..ae8d6d3 100644 --- a/src/main/kotlin/util/render/RenderInWorldContext.kt +++ b/src/main/kotlin/util/render/RenderInWorldContext.kt @@ -8,14 +8,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 @@ -47,7 +45,7 @@ class RenderInWorldContext private constructor( RenderLayer.MultiPhaseParameters.builder() .depthTest(RenderPhase.ALWAYS_DEPTH_TEST) .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) - .program(RenderPhase.COLOR_PROGRAM) + .program(RenderPhase.POSITION_COLOR_PROGRAM) .build(false)) val LINES = RenderLayer.of("firmament_rendertype_lines", VertexFormats.LINES, @@ -72,7 +70,7 @@ class RenderInWorldContext private constructor( fun block(blockPos: BlockPos) { matrixStack.push() matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) - buildCube(matrixStack.peek().positionMatrix, tesselator) + buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayer.getDebugFilledBox())) matrixStack.pop() } @@ -136,22 +134,24 @@ class RenderInWorldContext private constructor( } fun tinyBlock(vec3d: Vec3d, size: Float) { - RenderSystem.setShader(GameRenderer::getPositionColorProgram) + val buf = vertexConsumers.getBuffer(RenderLayer.getDebugFilledBox()) // TODO: custom rendewr layer here, maybe 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) + buildCube(matrixStack.peek().positionMatrix, buf) matrixStack.pop() + vertexConsumers.draw() } fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) { - RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) + val buf = vertexConsumers.getBuffer(RenderLayer.LINES) 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() + buildWireFrameCube(matrixStack.peek(), buf) + matrixStack.pop() + vertexConsumers.draw() } fun line(vararg points: Vec3d, lineWidth: Float = 10F) { @@ -165,6 +165,7 @@ class RenderInWorldContext private constructor( 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() @@ -191,7 +192,7 @@ class RenderInWorldContext private constructor( companion object { private fun doLine( matrix: MatrixStack.Entry, - buf: BufferBuilder, + buf: VertexConsumer, i: Float, j: Float, k: Float, @@ -213,9 +214,7 @@ class RenderInWorldContext private constructor( } - private fun buildWireFrameCube(matrix: MatrixStack.Entry, tessellator: Tessellator) { - val buf = tessellator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) - + private fun buildWireFrameCube(matrix: MatrixStack.Entry, buf: VertexConsumer) { for (i in 0..1) { for (j in 0..1) { val i = i.toFloat() @@ -225,11 +224,9 @@ class RenderInWorldContext private constructor( 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) + private fun buildCube(matrix: Matrix4f, buf: VertexConsumer) { 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() @@ -266,7 +263,6 @@ class RenderInWorldContext private constructor( 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()) } |