aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin')
-rw-r--r--src/main/kotlin/events/BakeExtraModelsEvent.kt25
-rw-r--r--src/main/kotlin/events/CustomItemModelEvent.kt46
-rw-r--r--src/main/kotlin/events/FinalizeResourceManagerEvent.kt41
-rw-r--r--src/main/kotlin/events/IsSlotProtectedEvent.kt2
-rw-r--r--src/main/kotlin/events/RegisterCustomShadersEvent.kt24
-rw-r--r--src/main/kotlin/events/SlotRenderEvents.kt15
-rw-r--r--src/main/kotlin/features/chat/ChatLinks.kt3
-rw-r--r--src/main/kotlin/features/debug/DeveloperFeatures.kt4
-rw-r--r--src/main/kotlin/features/debug/PowerUserTools.kt17
-rw-r--r--src/main/kotlin/features/inventory/CraftingOverlay.kt2
-rw-r--r--src/main/kotlin/features/inventory/ItemRarityCosmetics.kt16
-rw-r--r--src/main/kotlin/features/inventory/PetFeatures.kt5
-rw-r--r--src/main/kotlin/features/inventory/SlotLocking.kt25
-rw-r--r--src/main/kotlin/features/inventory/buttons/InventoryButton.kt5
-rw-r--r--src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt1
-rw-r--r--src/main/kotlin/features/inventory/storageoverlay/StorageBackingHandle.kt1
-rw-r--r--src/main/kotlin/features/inventory/storageoverlay/StorageOverlayScreen.kt7
-rw-r--r--src/main/kotlin/features/inventory/storageoverlay/StorageOverviewScreen.kt2
-rw-r--r--src/main/kotlin/features/mining/CommissionFeatures.kt8
-rw-r--r--src/main/kotlin/features/mining/HotmPresets.kt7
-rw-r--r--src/main/kotlin/features/texturepack/CustomBlockTextures.kt4
-rw-r--r--src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt213
-rw-r--r--src/main/kotlin/features/texturepack/CustomGlobalTextures.kt2
-rw-r--r--src/main/kotlin/features/world/Waypoints.kt499
-rw-r--r--src/main/kotlin/gui/BarComponent.kt182
-rw-r--r--src/main/kotlin/gui/entity/EntityRenderer.kt3
-rw-r--r--src/main/kotlin/gui/entity/FakeWorld.kt695
-rw-r--r--src/main/kotlin/gui/entity/ModifyHorse.kt11
-rw-r--r--src/main/kotlin/repo/RepoDownloadManager.kt2
-rw-r--r--src/main/kotlin/repo/RepoManager.kt6
-rw-r--r--src/main/kotlin/util/MC.kt2
-rw-r--r--src/main/kotlin/util/data/IDataHolder.kt112
-rw-r--r--src/main/kotlin/util/render/DrawContextExt.kt50
-rw-r--r--src/main/kotlin/util/render/FacingThePlayerContext.kt7
-rw-r--r--src/main/kotlin/util/render/FirmamentShaders.kt19
-rw-r--r--src/main/kotlin/util/render/RenderCircleProgress.kt140
-rw-r--r--src/main/kotlin/util/render/RenderInWorldContext.kt32
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())
}