1.21.3 WIP

This commit is contained in:
Linnea Gräf
2024-11-03 01:24:24 +01:00
parent 646843ba3b
commit 22f0cc59a2
105 changed files with 2854 additions and 2646 deletions

View File

@@ -18,7 +18,7 @@ SPDX-License-Identifier = "CC-BY-4.0"
SPDX-FileCopyrightText = ["Linnea Gräf <nea@nea.moe>", "Firmament Contributors"] SPDX-FileCopyrightText = ["Linnea Gräf <nea@nea.moe>", "Firmament Contributors"]
[[annotations]] [[annotations]]
path = ["src/main/resources/assets/minecraft/shaders/core/**/*"] path = ["src/main/resources/assets/firmament/shaders/**/*"]
SPDX-License-Identifier = "GPL-3.0-or-later" SPDX-License-Identifier = "GPL-3.0-or-later"
SPDX-FileCopyrightText = ["Linnea Gräf <nea@nea.moe>", "Firmament Contributors"] SPDX-FileCopyrightText = ["Linnea Gräf <nea@nea.moe>", "Firmament Contributors"]

View File

@@ -21,7 +21,9 @@ plugins {
alias(libs.plugins.kotlin.plugin.serialization) alias(libs.plugins.kotlin.plugin.serialization)
alias(libs.plugins.kotlin.plugin.powerassert) alias(libs.plugins.kotlin.plugin.powerassert)
alias(libs.plugins.kotlin.plugin.ksp) alias(libs.plugins.kotlin.plugin.ksp)
alias(libs.plugins.loom) // alias(libs.plugins.loom)
// TODO: use arch loom once they update to 1.8
id("fabric-loom") version "1.8.9"
id("com.github.johnrengelman.shadow") version "8.1.1" id("com.github.johnrengelman.shadow") version "8.1.1"
id("moe.nea.licenseextractificator") id("moe.nea.licenseextractificator")
id("moe.nea.mc-auto-translations") version "0.0.1" id("moe.nea.mc-auto-translations") version "0.0.1"
@@ -104,16 +106,12 @@ fun String.capitalizeN() = replaceFirstChar { it.uppercaseChar() }
val unpackAllJars by tasks.registering val unpackAllJars by tasks.registering
fun innerJarsOf(name: String, dependency: Dependency): Provider<FileTree> { fun innerJarsOf(name: String, dependency: Dependency): Provider<FileTree> {
val task = tasks.create("unpackInnerJarsFor${name.capitalizeN()}", InnerJarsUnpacker::class) { val task = tasks.create("unpackInnerJarsFor${name.capitalizeN()}", InnerJarsUnpacker::class) {
doFirst {
println("Unpacking JARs for $name")
}
this.inputJars.setFrom(files(configurations.detachedConfiguration(dependency))) this.inputJars.setFrom(files(configurations.detachedConfiguration(dependency)))
this.outputDir.set(layout.buildDirectory.dir("unpackedJars/$name").also { this.outputDir.set(layout.buildDirectory.dir("unpackedJars/$name").also {
it.get().asFile.mkdirs() it.get().asFile.mkdirs()
}) })
} }
unpackAllJars { dependsOn(task) } unpackAllJars { dependsOn(task) }
println("Constructed innerJars task: ${project.files(task).asFileTree.toList().map {it to it.exists()}}")
return project.provider { return project.provider {
project.files(task).asFileTree project.files(task).asFileTree
} }
@@ -125,15 +123,32 @@ val collectTranslations by tasks.registering(CollectTranslations::class) {
} }
val compatSourceSets: MutableSet<SourceSet> = mutableSetOf() val compatSourceSets: MutableSet<SourceSet> = mutableSetOf()
fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): SourceSet { fun createIsolatedSourceSet(name: String, path: String = "compat/$name", isEnabled: Boolean = true): SourceSet {
val ss = sourceSets.create(name) { val ss = sourceSets.create(name) {
if (isEnabled) {
this.java.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java"))) this.java.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java")))
this.kotlin.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java"))) this.kotlin.setSrcDirs(listOf(layout.projectDirectory.dir("src/$path/java")))
} else {
this.java.setSrcDirs(listOf<File>())
this.kotlin.setSrcDirs(listOf<File>())
}
}
val mainSS = sourceSets.main.get()
val upperName = ss.name.capitalizeN()
afterEvaluate {
tasks.named("ksp${upperName}Kotlin", KspTaskJvm::class) {
this.options.add(SubpluginOption("apoption", "firmament.sourceset=${ss.name}"))
}
tasks.named("compile${upperName}Kotlin", KotlinCompile::class) {
this.enabled = isEnabled
}
tasks.named("compile${upperName}Java", JavaCompile::class) {
this.enabled = isEnabled
}
} }
compatSourceSets.add(ss) compatSourceSets.add(ss)
loom.createRemapConfigurations(ss) loom.createRemapConfigurations(ss)
val mainSS = sourceSets.main.get() if (!isEnabled) return ss
val upperName = ss.name.capitalizeN()
configurations { configurations {
(ss.implementationConfigurationName) { (ss.implementationConfigurationName) {
extendsFrom(getByName(mainSS.compileClasspathConfigurationName)) extendsFrom(getByName(mainSS.compileClasspathConfigurationName))
@@ -148,11 +163,6 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name"): Source
extendsFrom(ksp.get()) extendsFrom(ksp.get())
} }
} }
afterEvaluate {
tasks.named("ksp${upperName}Kotlin", KspTaskJvm::class) {
this.options.add(SubpluginOption("apoption", "firmament.sourceset=${ss.name}"))
}
}
dependencies { dependencies {
runtimeOnly(ss.output) runtimeOnly(ss.output)
(ss.implementationConfigurationName)(sourceSets.main.get().output) (ss.implementationConfigurationName)(sourceSets.main.get().output)
@@ -195,14 +205,15 @@ val nonModImplentation by configurations.creating {
} }
val configuredSourceSet = createIsolatedSourceSet("configured") val configuredSourceSet = createIsolatedSourceSet("configured",
isEnabled = false) // Wait for update (also low prio, because configured sucks)
val sodiumSourceSet = createIsolatedSourceSet("sodium") val sodiumSourceSet = createIsolatedSourceSet("sodium")
val citResewnSourceSet = createIsolatedSourceSet("citresewn") val citResewnSourceSet = createIsolatedSourceSet("citresewn", isEnabled = false) // TODO: Wait for update
val yaclSourceSet = createIsolatedSourceSet("yacl") val yaclSourceSet = createIsolatedSourceSet("yacl")
val explosiveEnhancementSourceSet = createIsolatedSourceSet("explosiveEnhancement") val explosiveEnhancementSourceSet = createIsolatedSourceSet("explosiveEnhancement", isEnabled = false) // TODO: wait for their port
val wildfireGenderSourceSet = createIsolatedSourceSet("wildfireGender") val wildfireGenderSourceSet = createIsolatedSourceSet("wildfireGender", isEnabled = false) // TODO: wait on their port
val modmenuSourceSet = createIsolatedSourceSet("modmenu") val modmenuSourceSet = createIsolatedSourceSet("modmenu")
val reiSourceSet = createIsolatedSourceSet("rei") val reiSourceSet = createIsolatedSourceSet("rei") // TODO: read through https://hackmd.io/@shedaniel/rei17_primer
dependencies { dependencies {
// Minecraft dependencies // Minecraft dependencies
@@ -299,7 +310,7 @@ loom {
compatSourceSets.joinToString(File.pathSeparator) { compatSourceSets.joinToString(File.pathSeparator) {
File(it.output.classesDirs.asPath).absolutePath File(it.output.classesDirs.asPath).absolutePath
}) })
property("mixin.debug", "true") property("mixin.debug.export", "true")
parseEnvFile(file(".env")).forEach { (t, u) -> parseEnvFile(file(".env")).forEach { (t, u) ->
environmentVariable(t, u) environmentVariable(t, u)
@@ -360,7 +371,7 @@ tasks.shadowJar {
} }
tasks.remapJar { tasks.remapJar {
injectAccessWidener.set(true) // injectAccessWidener.set(true)
inputFile.set(tasks.shadowJar.flatMap { it.archiveFile }) inputFile.set(tasks.shadowJar.flatMap { it.archiveFile })
dependsOn(tasks.shadowJar) dependsOn(tasks.shadowJar)
archiveClassifier.set("") archiveClassifier.set("")

View File

@@ -3,36 +3,36 @@
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
[versions] [versions]
minecraft = "1.21" minecraft = "1.21.3"
# Update from https://kotlinlang.org/ # Update from https://kotlinlang.org/
kotlin = "2.0.20" kotlin = "2.0.21"
# Update from https://github.com/google/ksp/releases # Update from https://github.com/google/ksp/releases
kotlin_ksp = "2.0.20-1.0.24" kotlin_ksp = "2.0.21-1.0.26"
# Update from https://linkie.shedaniel.me/dependencies?loader=fabric # Update from https://linkie.shedaniel.me/dependencies?loader=fabric
fabric_loader = "0.16.3" fabric_loader = "0.16.9"
fabric_api = "0.100.4+1.21" fabric_api = "0.107.0+1.21.3"
fabric_kotlin = "1.11.0+kotlin.2.0.0" fabric_kotlin = "1.12.3+kotlin.2.0.21"
yarn = "1.21+build.7" yarn = "1.21.3+build.2"
rei = "16.0.729" rei = "17.0.789"
modmenu = "11.0.1" modmenu = "12.0.0-beta.1"
architectury = "13.0.3" architectury = "14.0.4"
# Update from https://maven.architectury.dev/dev/architectury/loom/dev.architectury.loom.gradle.plugin/ # Update from https://maven.architectury.dev/dev/architectury/loom/dev.architectury.loom.gradle.plugin/
loom = "1.7.412" loom = "1.7.414"
# Update from https://modrinth.com/mod/qolify/versions?l=fabric # Update from https://modrinth.com/mod/qolify/versions?l=fabric
qolify = "1.6.0-1.21.1" qolify = "1.6.0-1.21.1"
# Update from https://modrinth.com/mod/sodium/versions?l=fabric # Update from https://modrinth.com/mod/sodium/versions?l=fabric
sodium = "mc1.21-0.5.11" sodium = "mc1.21.3-0.6.0-beta.4-fabric"
# Update from https://modrinth.com/mod/freecam/versions?l=fabric # Update from https://modrinth.com/mod/freecam/versions?l=fabric
freecammod = "vomskVK3" freecammod = "vomskVK3"
# Update from https://modrinth.com/mod/no-chat-reports/versions?l=fabric # Update from https://modrinth.com/mod/no-chat-reports/versions?l=fabric
ncr = "Fabric-1.21-v2.8.0" ncr = "Fabric-1.21.3-v2.10.0"
# Update from https://modrinth.com/mod/female-gender/versions?l=fabric # Update from https://modrinth.com/mod/female-gender/versions?l=fabric
femalegender = "kJmjQvAS" femalegender = "kJmjQvAS"
@@ -49,7 +49,7 @@ citresewn = "1.2.0+1.21"
devauth = "1.2.0" devauth = "1.2.0"
# Update from https://ktor.io/ # Update from https://ktor.io/
ktor = "2.3.12" ktor = "3.0.1"
# Update from https://repo.nea.moe/#/releases/moe/nea/neurepoparser # Update from https://repo.nea.moe/#/releases/moe/nea/neurepoparser
neurepoparser = "1.6.0" neurepoparser = "1.6.0"
@@ -58,13 +58,13 @@ neurepoparser = "1.6.0"
hotswap_agent = "1.4.2-SNAPSHOT" hotswap_agent = "1.4.2-SNAPSHOT"
# Update from https://github.com/LlamaLad7/MixinExtras/tags # Update from https://github.com/LlamaLad7/MixinExtras/tags
mixinextras = "0.3.5" mixinextras = "0.4.1"
jarvis = "1.1.3" jarvis = "1.1.3"
nealisp = "1.0.0" nealisp = "1.1.0"
# Update from https://github.com/NotEnoughUpdates/MoulConfig/tags # Update from https://github.com/NotEnoughUpdates/MoulConfig/tags
moulconfig = "3.0.0-beta.15" moulconfig = "3.0.0"
# Update from https://www.curseforge.com/minecraft/mc-mods/configured/files/all?page=1&pageSize=20 # Update from https://www.curseforge.com/minecraft/mc-mods/configured/files/all?page=1&pageSize=20
configured = "5441234" configured = "5441234"
@@ -77,7 +77,7 @@ hypixelmodapi_fabric = "1.0.1+build.1+mc1.21"
manninghamMills = "2.4.1" manninghamMills = "2.4.1"
# Update from https://docs.isxander.dev/yet-another-config-lib/installing-yacl # Update from https://docs.isxander.dev/yet-another-config-lib/installing-yacl
yacl = "3.5.0+1.21-fabric" yacl = "3.6.1+1.21.2-fabric"
# Update from https://maven.shedaniel.me/me/shedaniel/cloth/basic-math/0.6.1/ # Update from https://maven.shedaniel.me/me/shedaniel/cloth/basic-math/0.6.1/
basicMath = "0.6.1" basicMath = "0.6.1"
@@ -120,10 +120,8 @@ basicMath = { module = "me.shedaniel.cloth:basic-math", version.ref = "basicMath
[bundles] [bundles]
runtime_required = [ runtime_required = [
"architectury_fabric",
"rei_fabric", "rei_fabric",
"notenoughanimations", # "notenoughanimations",
"femalegender",
"hypixelmodapi_fabric", "hypixelmodapi_fabric",
] ]
runtime_optional = [ runtime_optional = [
@@ -132,7 +130,7 @@ runtime_optional = [
# "sodium", # "sodium",
# "qolify", # "qolify",
"ncr", "ncr",
"citresewn", # "citresewn",
] ]
[plugins] [plugins]

View File

@@ -4,10 +4,10 @@ import me.shedaniel.math.Dimension
import me.shedaniel.math.Point import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle import me.shedaniel.math.Rectangle
import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds
import moe.nea.firmament.gui.entity.EntityRenderer
import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.Element import net.minecraft.client.gui.Element
import net.minecraft.entity.LivingEntity import net.minecraft.entity.LivingEntity
import moe.nea.firmament.gui.entity.EntityRenderer
class EntityWidget(val entity: LivingEntity, val point: Point) : WidgetWithBounds() { class EntityWidget(val entity: LivingEntity, val point: Point) : WidgetWithBounds() {
override fun children(): List<Element> { override fun children(): List<Element> {

View File

@@ -0,0 +1,10 @@
package moe.nea.firmament.compat.rei
import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry
import me.shedaniel.rei.api.common.plugins.REICommonPlugin
class FirmamentReiCommonPlugin : REICommonPlugin {
override fun registerEntryTypes(registry: EntryTypeRegistry) {
registry.register(FirmamentReiPlugin.SKYBLOCK_ITEM_TYPE_ID, SBItemEntryDefinition)
}
}

View File

@@ -11,7 +11,6 @@ import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry
import me.shedaniel.rei.api.client.registry.transfer.TransferHandler import me.shedaniel.rei.api.client.registry.transfer.TransferHandler
import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry
import me.shedaniel.rei.api.common.entry.EntryStack import me.shedaniel.rei.api.common.entry.EntryStack
import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry
import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes
import net.minecraft.client.gui.screen.Screen import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen import net.minecraft.client.gui.screen.ingame.GenericContainerScreen
@@ -20,18 +19,17 @@ import net.minecraft.item.ItemStack
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.ActionResult import net.minecraft.util.ActionResult
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.events.HandledScreenPushREIEvent
import moe.nea.firmament.features.inventory.CraftingOverlay
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
import moe.nea.firmament.compat.rei.recipes.SBCraftingRecipe import moe.nea.firmament.compat.rei.recipes.SBCraftingRecipe
import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe import moe.nea.firmament.compat.rei.recipes.SBEssenceUpgradeRecipe
import moe.nea.firmament.compat.rei.recipes.SBForgeRecipe import moe.nea.firmament.compat.rei.recipes.SBForgeRecipe
import moe.nea.firmament.compat.rei.recipes.SBKatRecipe import moe.nea.firmament.compat.rei.recipes.SBKatRecipe
import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe import moe.nea.firmament.compat.rei.recipes.SBMobDropRecipe
import moe.nea.firmament.events.HandledScreenPushREIEvent
import moe.nea.firmament.features.inventory.CraftingOverlay
import moe.nea.firmament.features.inventory.storageoverlay.StorageOverlayScreen
import moe.nea.firmament.repo.RepoManager import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.repo.SBItemStack import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.ScreenUtil
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.guessRecipeId import moe.nea.firmament.util.guessRecipeId
import moe.nea.firmament.util.skyblockId import moe.nea.firmament.util.skyblockId
@@ -74,9 +72,6 @@ class FirmamentReiPlugin : REIClientPlugin {
}) })
} }
override fun registerEntryTypes(registry: EntryTypeRegistry) {
registry.register(SKYBLOCK_ITEM_TYPE_ID, SBItemEntryDefinition)
}
override fun registerCategories(registry: CategoryRegistry) { override fun registerCategories(registry: CategoryRegistry) {
registry.add(SBCraftingRecipe.Category) registry.add(SBCraftingRecipe.Category)

View File

@@ -21,6 +21,7 @@ class ScreenRegistryHoveredItemStackProvider : HoveredItemStackProvider {
return entryStack.value as? ItemStack ?: entryStack.cheatsAs().value return entryStack.value as? ItemStack ?: entryStack.cheatsAs().value
} }
} }
@AutoService(HoveredItemStackProvider::class) @AutoService(HoveredItemStackProvider::class)
@CompatLoader.RequireMod("roughlyenoughitems") @CompatLoader.RequireMod("roughlyenoughitems")
class OverlayHoveredItemStackProvider : HoveredItemStackProvider { class OverlayHoveredItemStackProvider : HoveredItemStackProvider {

View File

@@ -25,13 +25,13 @@ import net.minecraft.client.render.LightmapTextureManager
import net.minecraft.client.render.OverlayTexture import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.VertexConsumerProvider import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.model.BakedModel import net.minecraft.client.render.model.BakedModel
import net.minecraft.client.render.model.json.ModelTransformationMode
import net.minecraft.client.texture.SpriteAtlasTexture import net.minecraft.client.texture.SpriteAtlasTexture
import net.minecraft.item.Item import net.minecraft.item.ModelTransformationMode
import net.minecraft.item.ItemStack
import net.minecraft.item.tooltip.TooltipType
import moe.nea.firmament.compat.rei.FirmamentReiPlugin.Companion.asItemEntry import moe.nea.firmament.compat.rei.FirmamentReiPlugin.Companion.asItemEntry
import moe.nea.firmament.repo.SBItemStack import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt
object NEUItemEntryRenderer : EntryRenderer<SBItemStack>, BatchedEntryRenderer<SBItemStack, BakedModel> { object NEUItemEntryRenderer : EntryRenderer<SBItemStack>, BatchedEntryRenderer<SBItemStack, BakedModel> {
override fun render( override fun render(
@@ -49,139 +49,104 @@ object NEUItemEntryRenderer : EntryRenderer<SBItemStack>, BatchedEntryRenderer<S
override fun getTooltip(entry: EntryStack<SBItemStack>, tooltipContext: TooltipContext): Tooltip? { override fun getTooltip(entry: EntryStack<SBItemStack>, tooltipContext: TooltipContext): Tooltip? {
val stack = entry.value.asImmutableItemStack() val stack = entry.value.asImmutableItemStack()
val lore = stack.getTooltip(
Item.TooltipContext.DEFAULT, val lore = mutableListOf(stack.displayNameAccordingToNbt)
null, lore.addAll(stack.loreAccordingToNbt)
TooltipType.BASIC
) // TODO: tags aren't sent as early now so some tooltip components that use tags will crash the game
// stack.getTooltip(
// Item.TooltipContext.create(
// tooltipContext.vanillaContext().registryLookup
// ?: MC.defaultRegistries
// ),
// MC.player,
// TooltipType.BASIC
// )
return Tooltip.create(lore) return Tooltip.create(lore)
} }
override fun getExtraData(entry: EntryStack<SBItemStack>): BakedModel { override fun getExtraData(entry: EntryStack<SBItemStack>): BakedModel {
return minecraft.itemRenderer.getModel(entry.asItemEntry().value, minecraft.world, minecraft.player, 0) return MC.itemRenderer.getModel(entry.asItemEntry().value,
MC.world,
MC.player, 0)
} }
override fun getBatchIdentifier(entry: EntryStack<SBItemStack>?, bounds: Rectangle?, extraData: BakedModel): Int { override fun getBatchIdentifier(entry: EntryStack<SBItemStack>, bounds: Rectangle?, extraData: BakedModel): Int {
return 1738923 + if (extraData.isSideLit) 1 else 0 return 1738923 + if (extraData.isSideLit) 1 else 0
} }
override fun startBatch(
entry: EntryStack<SBItemStack>,
model: BakedModel,
graphics: DrawContext,
delta: Float
) {
val modelViewStack = RenderSystem.getModelViewStack()
modelViewStack.pushMatrix()
modelViewStack.scale(20.0f, 20.0f, 1.0f)
RenderSystem.applyModelViewMatrix()
setupGL(model)
}
fun setupGL(model: BakedModel) { override fun startBatch(entryStack: EntryStack<SBItemStack>, e: BakedModel, drawContext: DrawContext, v: Float) {
minecraft.textureManager.getTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE) MC.textureManager.getTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE)
.setFilter(false, false) .setFilter(false, false)
RenderSystem.setShaderTexture(0, SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE) RenderSystem.setShaderTexture(0, SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE)
RenderSystem.enableBlend() RenderSystem.enableBlend()
RenderSystem.blendFunc(SrcFactor.SRC_ALPHA, DstFactor.ONE_MINUS_SRC_ALPHA) RenderSystem.blendFunc(SrcFactor.SRC_ALPHA, DstFactor.ONE_MINUS_SRC_ALPHA)
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f) RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f)
val sideLit = model.isSideLit if (!e.isSideLit) {
if (!sideLit) {
DiffuseLighting.disableGuiDepthLighting() DiffuseLighting.disableGuiDepthLighting()
} }
} }
override fun renderBase( override fun renderBase(
entry: EntryStack<SBItemStack>, entryStack: EntryStack<SBItemStack>,
model: BakedModel, model: BakedModel,
graphics: DrawContext, drawContext: DrawContext,
immediate: VertexConsumerProvider.Immediate, immediate: VertexConsumerProvider.Immediate,
bounds: Rectangle, bounds: Rectangle,
mouseX: Int, i: Int,
mouseY: Int, i1: Int,
delta: Float v: Float
) { ) {
if (entry.isEmpty) return if (entryStack.isEmpty) return
val value = entry.asItemEntry().value drawContext.matrices.push()
graphics.matrices.push() drawContext.matrices.translate(bounds.centerX.toDouble(), bounds.centerY.toDouble(), 0.0)
graphics.matrices.translate(bounds.centerX.toFloat() / 20.0f, bounds.centerY.toFloat() / 20.0f, 0.0f) // TODO: check the scaling here again
graphics.matrices.scale( drawContext.matrices.scale(
bounds.getWidth().toFloat() / 20.0f, bounds.width.toFloat(),
-(bounds.getWidth() + bounds.getHeight()).toFloat() / 2.0f / 20.0f, (bounds.height + bounds.height) / -2F,
1.0f (bounds.width + bounds.height) / 2f)
) MC.itemRenderer.renderItem(
minecraft entryStack.value.asImmutableItemStack(),
.itemRenderer
.renderItem(
value,
ModelTransformationMode.GUI, ModelTransformationMode.GUI,
false, false, drawContext.matrices,
graphics.matrices, immediate, LightmapTextureManager.MAX_LIGHT_COORDINATE,
immediate,
LightmapTextureManager.MAX_LIGHT_COORDINATE,
OverlayTexture.DEFAULT_UV, OverlayTexture.DEFAULT_UV,
model model
) )
graphics.matrices.pop() drawContext.matrices.pop()
} }
override fun afterBase( override fun afterBase(entryStack: EntryStack<SBItemStack>?, e: BakedModel, drawContext: DrawContext?, v: Float) {
entry: EntryStack<SBItemStack>,
model: BakedModel,
graphics: DrawContext,
delta: Float
) {
RenderSystem.getModelViewStack().popMatrix()
RenderSystem.applyModelViewMatrix()
this.endGL(model)
}
fun endGL(model: BakedModel) {
RenderSystem.enableDepthTest() RenderSystem.enableDepthTest()
val sideLit = model.isSideLit if (!e.isSideLit)
if (!sideLit) {
DiffuseLighting.enableGuiDepthLighting() DiffuseLighting.enableGuiDepthLighting()
} }
}
override fun renderOverlay( override fun renderOverlay(
entry: EntryStack<SBItemStack>, entryStack: EntryStack<SBItemStack>,
extraData: BakedModel, e: BakedModel,
graphics: DrawContext, drawContext: DrawContext,
immediate: VertexConsumerProvider.Immediate, immediate: VertexConsumerProvider.Immediate,
bounds: Rectangle, bounds: Rectangle,
mouseX: Int, i: Int,
mouseY: Int, i1: Int,
delta: Float v: Float
) { ) {
if (entryStack.isEmpty) return
val modelViewStack = RenderSystem.getModelViewStack() val modelViewStack = RenderSystem.getModelViewStack()
modelViewStack.pushMatrix() modelViewStack.pushMatrix()
modelViewStack.mul(graphics.matrices.peek().positionMatrix) modelViewStack.mul(drawContext.matrices.peek().positionMatrix)
modelViewStack.translate(bounds.x.toFloat(), bounds.y.toFloat(), 0.0f) modelViewStack.translate(bounds.x.toFloat(), bounds.y.toFloat(), 0F)
modelViewStack.scale( modelViewStack.scale(bounds.width / 16.0f,
bounds.width.toFloat() / 16.0f, (bounds.width + bounds.height) / 2.0f / 16.0f,
-(bounds.getWidth() + bounds.getHeight()).toFloat() / 2.0f / 16.0f, 1.0f) // TODO: weird scale again
1.0f drawContext.drawStackOverlay(MC.font, entryStack.value.asImmutableItemStack(), 0, 0, null)
)
RenderSystem.applyModelViewMatrix()
renderOverlay(DrawContext(minecraft, graphics.vertexConsumers), entry.asItemEntry())
modelViewStack.popMatrix() modelViewStack.popMatrix()
RenderSystem.applyModelViewMatrix()
} }
fun renderOverlay(graphics: DrawContext, entry: EntryStack<ItemStack>) { override fun endBatch(entryStack: EntryStack<SBItemStack>?, e: BakedModel?, drawContext: DrawContext?, v: Float) {
if (!entry.isEmpty) {
graphics.drawItemInSlot(MinecraftClient.getInstance().textRenderer, entry.value, 0, 0, null)
}
}
override fun endBatch(
entry: EntryStack<SBItemStack>?,
extraData: BakedModel?,
graphics: DrawContext?,
delta: Float
) {
} }
} }

View File

@@ -1,30 +1,17 @@
package moe.nea.firmament.compat.rei package moe.nea.firmament.compat.rei
import com.mojang.serialization.Codec
import me.shedaniel.rei.api.common.entry.EntrySerializer import me.shedaniel.rei.api.common.entry.EntrySerializer
import me.shedaniel.rei.api.common.entry.EntryStack import net.minecraft.network.RegistryByteBuf
import net.minecraft.nbt.NbtCompound import net.minecraft.network.codec.PacketCodec
import moe.nea.firmament.repo.SBItemStack import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.SkyblockId
object NEUItemEntrySerializer : EntrySerializer<SBItemStack> { object NEUItemEntrySerializer : EntrySerializer<SBItemStack> {
const val SKYBLOCK_ID_ENTRY = "SKYBLOCK_ID" override fun codec(): Codec<SBItemStack> {
const val SKYBLOCK_ITEM_COUNT = "SKYBLOCK_ITEM_COUNT" return SBItemStack.CODEC
override fun supportSaving(): Boolean = true
override fun supportReading(): Boolean = true
override fun read(tag: NbtCompound): SBItemStack {
val id = SkyblockId(tag.getString(SKYBLOCK_ID_ENTRY))
val count = if (tag.contains(SKYBLOCK_ITEM_COUNT)) tag.getInt(SKYBLOCK_ITEM_COUNT) else 1
return SBItemStack(id, count)
} }
override fun save(entry: EntryStack<SBItemStack>, value: SBItemStack): NbtCompound { override fun streamCodec(): PacketCodec<RegistryByteBuf, SBItemStack> {
return NbtCompound().apply { return SBItemStack.PACKET_CODEC.cast()
putString(SKYBLOCK_ID_ENTRY, value.skyblockId.neuItem)
putInt(SKYBLOCK_ITEM_COUNT, value.getStackSize())
}
} }
} }

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.compat.rei package moe.nea.firmament.compat.rei
import me.shedaniel.math.Point import me.shedaniel.math.Point

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.compat.rei.recipes package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUCraftingRecipe import io.github.moulberry.repo.data.NEUCraftingRecipe
@@ -11,6 +9,8 @@ import me.shedaniel.rei.api.client.gui.widgets.Widget
import me.shedaniel.rei.api.client.gui.widgets.Widgets import me.shedaniel.rei.api.client.gui.widgets.Widgets
import me.shedaniel.rei.api.client.registry.display.DisplayCategory import me.shedaniel.rei.api.client.registry.display.DisplayCategory
import me.shedaniel.rei.api.common.category.CategoryIdentifier import me.shedaniel.rei.api.common.category.CategoryIdentifier
import me.shedaniel.rei.api.common.display.Display
import me.shedaniel.rei.api.common.display.DisplaySerializer
import me.shedaniel.rei.api.common.util.EntryStacks import me.shedaniel.rei.api.common.util.EntryStacks
import net.minecraft.block.Blocks import net.minecraft.block.Blocks
import net.minecraft.text.Text import net.minecraft.text.Text

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.compat.rei.recipes package moe.nea.firmament.compat.rei.recipes
import me.shedaniel.math.Point import me.shedaniel.math.Point

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.compat.rei.recipes package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUForgeRecipe import io.github.moulberry.repo.data.NEUForgeRecipe
@@ -39,7 +37,9 @@ class SBForgeRecipe(override val neuRecipe: NEUForgeRecipe) : SBRecipe() {
add(Widgets.createResultSlotBackground(Point(bounds.minX + 124, bounds.minY + 46))) add(Widgets.createResultSlotBackground(Point(bounds.minX + 124, bounds.minY + 46)))
val arrow = Widgets.createArrow(Point(bounds.minX + 90, bounds.minY + 54 - 18 / 2)) val arrow = Widgets.createArrow(Point(bounds.minX + 90, bounds.minY + 54 - 18 / 2))
add(arrow) add(arrow)
add(Widgets.createTooltip(arrow.bounds, Text.stringifiedTranslatable("firmament.recipe.forge.time", display.neuRecipe.duration.seconds))) add(Widgets.createTooltip(arrow.bounds,
Text.stringifiedTranslatable("firmament.recipe.forge.time",
display.neuRecipe.duration.seconds)))
val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8) val ingredientsCenter = Point(bounds.minX + 49 - 8, bounds.minY + 54 - 8)
val count = display.neuRecipe.inputs.size val count = display.neuRecipe.inputs.size
if (count == 1) { if (count == 1) {

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.compat.rei.recipes package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUKatUpgradeRecipe import io.github.moulberry.repo.data.NEUKatUpgradeRecipe
@@ -20,7 +19,6 @@ import me.shedaniel.rei.api.client.registry.display.DisplayCategory
import me.shedaniel.rei.api.common.category.CategoryIdentifier import me.shedaniel.rei.api.common.category.CategoryIdentifier
import me.shedaniel.rei.api.common.util.EntryStacks import me.shedaniel.rei.api.common.util.EntryStacks
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import net.minecraft.block.Blocks
import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.Element import net.minecraft.client.gui.Element
import net.minecraft.item.Items import net.minecraft.item.Items

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.compat.rei.recipes package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUMobDropRecipe import io.github.moulberry.repo.data.NEUMobDropRecipe
@@ -14,9 +13,9 @@ import net.minecraft.item.Items
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.gui.entity.EntityRenderer
import moe.nea.firmament.compat.rei.EntityWidget import moe.nea.firmament.compat.rei.EntityWidget
import moe.nea.firmament.compat.rei.SBItemEntryDefinition import moe.nea.firmament.compat.rei.SBItemEntryDefinition
import moe.nea.firmament.gui.entity.EntityRenderer
class SBMobDropRecipe(override val neuRecipe: NEUMobDropRecipe) : SBRecipe() { class SBMobDropRecipe(override val neuRecipe: NEUMobDropRecipe) : SBRecipe() {
override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier override fun getCategoryIdentifier(): CategoryIdentifier<*> = Category.categoryIdentifier

View File

@@ -2,12 +2,25 @@ package moe.nea.firmament.compat.rei.recipes
import io.github.moulberry.repo.data.NEUIngredient import io.github.moulberry.repo.data.NEUIngredient
import io.github.moulberry.repo.data.NEURecipe import io.github.moulberry.repo.data.NEURecipe
import java.util.Optional
import me.shedaniel.rei.api.common.display.Display import me.shedaniel.rei.api.common.display.Display
import me.shedaniel.rei.api.common.display.DisplaySerializer
import me.shedaniel.rei.api.common.entry.EntryIngredient import me.shedaniel.rei.api.common.entry.EntryIngredient
import net.minecraft.util.Identifier
import moe.nea.firmament.compat.rei.SBItemEntryDefinition import moe.nea.firmament.compat.rei.SBItemEntryDefinition
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
abstract class SBRecipe : Display { abstract class SBRecipe : Display {
override fun getDisplayLocation(): Optional<Identifier> {
// In theory, we could return a location for the neuRecipe here. (Something along the lines of neurepo:items/item_id.json/0 for the 0th recipe in the items/item_id.json recipes array).
return Optional.empty()
}
override fun getSerializer(): DisplaySerializer<out Display>? {
// While returning null here is discouraged, we are fine to do so, since this recipe will never travel through the network
return null
}
abstract val neuRecipe: NEURecipe abstract val neuRecipe: NEURecipe
override fun getInputEntries(): List<EntryIngredient> { override fun getInputEntries(): List<EntryIngredient> {
return neuRecipe.allInputs return neuRecipe.allInputs

View File

@@ -1,6 +1,6 @@
package moe.nea.firmament.compat.sodium package moe.nea.firmament.compat.sodium
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer
import moe.nea.firmament.mixins.accessor.sodium.AccessorSodiumWorldRenderer import moe.nea.firmament.mixins.accessor.sodium.AccessorSodiumWorldRenderer
class SodiumChunkReloader : Runnable { class SodiumChunkReloader : Runnable {

View File

@@ -1,7 +1,7 @@
package moe.nea.firmament.mixins.accessor.sodium; package moe.nea.firmament.mixins.accessor.sodium;
import me.jellysquid.mods.sodium.client.render.SodiumWorldRenderer; import net.caffeinemc.mods.sodium.client.render.SodiumWorldRenderer;
import me.jellysquid.mods.sodium.client.render.chunk.RenderSectionManager; import net.caffeinemc.mods.sodium.client.render.chunk.RenderSectionManager;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.Pseudo;
import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Accessor;

View File

@@ -3,8 +3,8 @@ package moe.nea.firmament.mixins.custommodels;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Local;
import me.jellysquid.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask;
import moe.nea.firmament.features.texturepack.CustomBlockTextures; import moe.nea.firmament.features.texturepack.CustomBlockTextures;
import net.caffeinemc.mods.sodium.client.render.chunk.compile.tasks.ChunkBuilderMeshingTask;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.render.block.BlockModels; import net.minecraft.client.render.block.BlockModels;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
@@ -15,7 +15,7 @@ import org.spongepowered.asm.mixin.injection.At;
@Mixin(ChunkBuilderMeshingTask.class) @Mixin(ChunkBuilderMeshingTask.class)
public class PatchBlockModelInSodiumChunkGenerator { public class PatchBlockModelInSodiumChunkGenerator {
@WrapOperation( @WrapOperation(
method = "execute(Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lme/jellysquid/mods/sodium/client/util/task/CancellationToken;)Lme/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;", method = "execute(Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext;Lnet/caffeinemc/mods/sodium/client/util/task/CancellationToken;)Lnet/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput;",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModels;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;")) at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModels;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;"))
private BakedModel replaceBlockModel(BlockModels instance, BlockState state, Operation<BakedModel> original, private BakedModel replaceBlockModel(BlockModels instance, BlockState state, Operation<BakedModel> original,
@Local(name = "blockPos") BlockPos.Mutable pos) { @Local(name = "blockPos") BlockPos.Mutable pos) {

View File

@@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.At;
@Mixin(DrawContext.class) @Mixin(DrawContext.class)
public class CustomDurabilityBarPatch { public class CustomDurabilityBarPatch {
@WrapOperation( @WrapOperation(
method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", method = "drawItemBar",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isItemBarVisible()Z") at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isItemBarVisible()Z")
) )
private boolean onIsItemBarVisible( private boolean onIsItemBarVisible(
@@ -29,7 +29,7 @@ public class CustomDurabilityBarPatch {
return barOverride.get() != null; return barOverride.get() != null;
} }
@WrapOperation(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", @WrapOperation(method = "drawItemBar",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarStep()I")) at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarStep()I"))
private int overrideItemStep( private int overrideItemStep(
ItemStack instance, Operation<Integer> original, ItemStack instance, Operation<Integer> original,
@@ -40,7 +40,7 @@ public class CustomDurabilityBarPatch {
return original.call(instance); return original.call(instance);
} }
@WrapOperation(method = "drawItemInSlot(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", @WrapOperation(method = "drawItemBar",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarColor()I")) at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getItemBarColor()I"))
private int overrideItemColor( private int overrideItemColor(
ItemStack instance, Operation<Integer> original, ItemStack instance, Operation<Integer> original,

View File

@@ -1,49 +0,0 @@
package moe.nea.firmament.mixins;
import moe.nea.firmament.events.BakeExtraModelsEvent;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(ModelLoader.class)
public abstract class CustomModelBakerPatch {
@Shadow
@Final
private Map<ModelIdentifier, UnbakedModel> modelsToBake;
@Shadow
protected abstract void loadItemModel(ModelIdentifier id);
@Shadow
abstract UnbakedModel getOrLoadModel(Identifier id);
@Shadow
protected abstract void add(ModelIdentifier id, UnbakedModel model);
@Unique
private void loadNonItemModel(ModelIdentifier identifier) {
UnbakedModel unbakedModel = this.getOrLoadModel(identifier.id());
this.add(identifier, unbakedModel);
}
@Inject(method = "bake", at = @At("HEAD"))
public void onBake(ModelLoader.SpriteGetter spliteGetter, CallbackInfo ci) {
BakeExtraModelsEvent.Companion.publish(new BakeExtraModelsEvent(this::loadItemModel, this::loadNonItemModel));
modelsToBake.values().forEach(model -> model.setParents(this::getOrLoadModel));
// modelsToBake.keySet().stream()
// .filter(it -> !it.id().getNamespace().equals("minecraft"))
// .forEach(it -> System.out.println("Non minecraft texture is being loaded: " + it));
}
}

View File

@@ -7,6 +7,7 @@ import net.minecraft.client.render.item.ItemModels;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedModelManager; import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@@ -14,15 +15,14 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map;
@Mixin(ItemModels.class) @Mixin(ItemModels.class)
public class CustomModelEventPatch { public class CustomModelEventPatch {
@Shadow
@Final
private BakedModelManager modelManager;
@Inject(method = "getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true) @Inject(method = "getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true)
public void onGetModel(ItemStack stack, CallbackInfoReturnable<BakedModel> cir) { public void onGetModel(ItemStack stack, CallbackInfoReturnable<BakedModel> cir) {
var model = CustomItemModelEvent.getModel(stack, modelManager); var model = CustomItemModelEvent.getModel(stack, (ItemModels) (Object) this);
if (model != null) if (model != null)
cir.setReturnValue(model); cir.setReturnValue(model);
} }

View File

@@ -2,7 +2,6 @@
package moe.nea.firmament.mixins; package moe.nea.firmament.mixins;
import com.mojang.authlib.GameProfile;
import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures; import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures;
import net.minecraft.block.SkullBlock; import net.minecraft.block.SkullBlock;
import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.RenderLayer;

View File

@@ -17,6 +17,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map; import java.util.Map;
// TODO: rework this
@Mixin(EntityIdFix.class) @Mixin(EntityIdFix.class)
public abstract class DFUEntityIdFixPatch extends DataFix { public abstract class DFUEntityIdFixPatch extends DataFix {
@Shadow @Shadow

View File

@@ -1,31 +0,0 @@
package moe.nea.firmament.mixins;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.datafixers.util.Pair;
import moe.nea.firmament.events.RegisterCustomShadersEvent;
import net.minecraft.client.gl.ShaderProgram;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.resource.ResourceFactory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.function.Consumer;
@Mixin(GameRenderer.class)
public class InjectCustomShaderPrograms {
@Inject(method = "loadPrograms",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;loadBlurPostProcessor(Lnet/minecraft/resource/ResourceFactory;)V",
shift = At.Shift.AFTER))
void addFirmamentShaders(
ResourceFactory resourceFactory, CallbackInfo ci,
@Local(index = 3) List<Pair<ShaderProgram, Consumer<ShaderProgram>>> list
) {
var event = new RegisterCustomShadersEvent(list, resourceFactory);
RegisterCustomShadersEvent.Companion.publish(event);
}
}

View File

@@ -0,0 +1,31 @@
package moe.nea.firmament.mixins;
import moe.nea.firmament.Firmament;
import moe.nea.firmament.events.DebugInstantiateEvent;
import net.minecraft.client.gui.LogoDrawer;
import net.minecraft.client.gui.screen.TitleScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TitleScreen.class)
public class MainWindowFirstLoadPatch {
@Unique
private static boolean hasInited = false;
@Inject(method = "<init>(ZLnet/minecraft/client/gui/LogoDrawer;)V", at = @At("RETURN"))
private void onCreate(boolean doBackgroundFade, LogoDrawer logoDrawer, CallbackInfo ci) {
if (!hasInited) {
try {
DebugInstantiateEvent.Companion.publish(new DebugInstantiateEvent());
} catch (Throwable t) {
Firmament.INSTANCE.getLogger().error("Failed to instantiate debug instances", t);
System.exit(1);
throw t;
}
}
hasInited = true;
}
}

View File

@@ -2,6 +2,9 @@
package moe.nea.firmament.mixins; package moe.nea.firmament.mixins;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.events.*; import moe.nea.firmament.events.*;
import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
@@ -21,6 +24,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.Iterator;
@Mixin(HandledScreen.class) @Mixin(HandledScreen.class)
public abstract class MixinHandledScreen<T extends ScreenHandler> { public abstract class MixinHandledScreen<T extends ScreenHandler> {
@@ -90,15 +95,12 @@ public abstract class MixinHandledScreen<T extends ScreenHandler> {
} }
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD) @WrapOperation(method = "drawSlots", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V"))
public void onAfterDrawSlot(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci, int i, int j, int k, Slot slot) { public void onDrawSlots(HandledScreen instance, DrawContext context, Slot slot, Operation<Void> original) {
SlotRenderEvents.After event = new SlotRenderEvents.After(context, slot, mouseX, mouseY, delta); var before = new SlotRenderEvents.Before(context, slot);
SlotRenderEvents.After.Companion.publish(event); SlotRenderEvents.Before.Companion.publish(before);
} original.call(instance, context, slot);
var after = new SlotRenderEvents.After(context, slot);
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD) SlotRenderEvents.After.Companion.publish(after);
public void onBeforeDrawSlot(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci, int i, int j, int k, Slot slot) {
SlotRenderEvents.Before event = new SlotRenderEvents.Before(context, slot, mouseX, mouseY, delta);
SlotRenderEvents.Before.Companion.publish(event);
} }
} }

View File

@@ -20,12 +20,16 @@ import org.spongepowered.asm.mixin.injection.At;
AnvilScreen.class, BeaconScreen.class}) AnvilScreen.class, BeaconScreen.class})
public class ReplaceTextColorInHandledScreen { public class ReplaceTextColorInHandledScreen {
// To my future self: double check those mixins, but don't be too concerned about errors. Some of the wrapopertions
// only apply in some of the specified subclasses.
@WrapOperation( @WrapOperation(
method = "drawForeground", method = "drawForeground",
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
target = "Lnet/minecraft/client/gui/DrawContext;drawText(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;IIIZ)I"), target = "Lnet/minecraft/client/gui/DrawContext;drawText(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;IIIZ)I"),
expect = 0) expect = 0,
require = 0)
private int replaceTextColorWithVariableShadow(DrawContext instance, TextRenderer textRenderer, Text text, int x, int y, int color, boolean shadow, Operation<Integer> original) { private int replaceTextColorWithVariableShadow(DrawContext instance, TextRenderer textRenderer, Text text, int x, int y, int color, boolean shadow, Operation<Integer> original) {
return original.call(instance, textRenderer, text, x, y, CustomTextColors.INSTANCE.mapTextColor(text, color), shadow); return original.call(instance, textRenderer, text, x, y, CustomTextColors.INSTANCE.mapTextColor(text, color), shadow);
} }
@@ -35,7 +39,8 @@ public class ReplaceTextColorInHandledScreen {
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
target = "Lnet/minecraft/client/gui/DrawContext;drawTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;III)I"), target = "Lnet/minecraft/client/gui/DrawContext;drawTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;III)I"),
expect = 0) expect = 0,
require = 0)
private int replaceTextColorWithShadow(DrawContext instance, TextRenderer textRenderer, Text text, int x, int y, int color, Operation<Integer> original) { private int replaceTextColorWithShadow(DrawContext instance, TextRenderer textRenderer, Text text, int x, int y, int color, Operation<Integer> original) {
return original.call(instance, textRenderer, text, x, y, CustomTextColors.INSTANCE.mapTextColor(text, color)); return original.call(instance, textRenderer, text, x, y, CustomTextColors.INSTANCE.mapTextColor(text, color));
} }

View File

@@ -23,14 +23,13 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler {
@Inject( @Inject(
method = "onScreenHandlerSlotUpdate", method = "onScreenHandlerSlotUpdate",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/tutorial/TutorialManager;onSlotUpdate(Lnet/minecraft/item/ItemStack;)V")) at = @At(value = "TAIL"))
private void onSingleSlotUpdate( private void onSingleSlotUpdate(
ScreenHandlerSlotUpdateS2CPacket packet, ScreenHandlerSlotUpdateS2CPacket packet,
CallbackInfo ci) { CallbackInfo ci) {
var player = this.client.player; var player = this.client.player;
assert player != null; assert player != null;
if (packet.getSyncId() == ScreenHandlerSlotUpdateS2CPacket.UPDATE_PLAYER_INVENTORY_SYNC_ID if (packet.getSyncId() == 0) {
|| packet.getSyncId() == 0) {
PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Single(packet.getSlot(), packet.getStack())); PlayerInventoryUpdate.Companion.publish(new PlayerInventoryUpdate.Single(packet.getSlot(), packet.getStack()));
} else if (packet.getSyncId() == player.currentScreenHandler.syncId) { } else if (packet.getSyncId() == player.currentScreenHandler.syncId) {
ChestInventoryUpdateEvent.Companion.publish( ChestInventoryUpdateEvent.Companion.publish(
@@ -40,8 +39,7 @@ public abstract class SlotUpdateListener extends ClientCommonNetworkHandler {
} }
@Inject(method = "onInventory", @Inject(method = "onInventory",
at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/util/thread/ThreadExecutor;)V", at = @At("TAIL"))
shift = At.Shift.AFTER))
private void onMultiSlotUpdate(InventoryS2CPacket packet, CallbackInfo ci) { private void onMultiSlotUpdate(InventoryS2CPacket packet, CallbackInfo ci) {
var player = this.client.player; var player = this.client.player;
assert player != null; assert player != null;

View File

@@ -3,15 +3,16 @@
package moe.nea.firmament.mixins; package moe.nea.firmament.mixins;
import moe.nea.firmament.events.WorldReadyEvent; import moe.nea.firmament.events.WorldReadyEvent;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.DownloadingTerrainScreen; import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(DownloadingTerrainScreen.class) @Mixin(MinecraftClient.class)
public class WorldReadyEventPatch { public class WorldReadyEventPatch {
@Inject(method = "close", at = @At("HEAD")) @Inject(method = "joinWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;setWorld(Lnet/minecraft/client/world/ClientWorld;)V", shift = At.Shift.AFTER))
public void onClose(CallbackInfo ci) { public void onClose(CallbackInfo ci) {
WorldReadyEvent.Companion.publish(new WorldReadyEvent()); WorldReadyEvent.Companion.publish(new WorldReadyEvent());
} }

View File

@@ -5,8 +5,10 @@ package moe.nea.firmament.mixins;
import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.events.WorldRenderLastEvent; import moe.nea.firmament.events.WorldRenderLastEvent;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.util.Handle;
import net.minecraft.client.util.ObjectAllocator;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.world.tick.TickManager; import net.minecraft.util.profiler.Profiler;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@@ -16,22 +18,30 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(WorldRenderer.class) @Mixin(WorldRenderer.class)
public class WorldRenderLastEventPatch { public abstract class WorldRenderLastEventPatch {
@Shadow @Shadow
@Final @Final
private BufferBuilderStorage bufferBuilders; private BufferBuilderStorage bufferBuilders;
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/WorldRenderer;renderChunkDebugInfo(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/client/render/Camera;)V", shift = At.Shift.BEFORE)) @Shadow
public void onWorldRenderLast( @Final
RenderTickCounter tickCounter, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, private DefaultFramebufferSet framebufferSet;
LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, Matrix4f matrix4f2,
CallbackInfo ci, @Local MatrixStack matrixStack @Shadow
) { protected abstract void checkEmpty(MatrixStack matrices);
@Inject(method = "method_62214", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiler/Profiler;pop()V", shift = At.Shift.AFTER))
public void onWorldRenderLast(Fog fog, RenderTickCounter tickCounter, Camera camera, Profiler profiler, Matrix4f matrix4f, Matrix4f matrix4f2, Handle handle, Handle handle2, Handle handle3, Handle handle4, boolean bl, Frustum frustum, Handle handle5, CallbackInfo ci) {
var imm = this.bufferBuilders.getEntityVertexConsumers();
var stack = new MatrixStack();
// TODO: pre-cancel this event if F1 is active
var event = new WorldRenderLastEvent( var event = new WorldRenderLastEvent(
matrixStack, tickCounter, renderBlockOutline, stack, tickCounter,
camera, gameRenderer, lightmapTextureManager, camera,
this.bufferBuilders.getEntityVertexConsumers() imm
); );
WorldRenderLastEvent.Companion.publish(event); WorldRenderLastEvent.Companion.publish(event);
imm.draw();
checkEmpty(stack);
} }
} }

View File

@@ -1,14 +0,0 @@
package moe.nea.firmament.mixins.accessor;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.GameRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(GameRenderer.class)
public interface AccessorGameRenderer {
@Invoker("getFov")
double getFov_firmament(Camera camera, float tickDelta, boolean changingFov);
}

View File

@@ -14,7 +14,6 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.collection.DefaultedList;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@@ -88,29 +87,18 @@ public class PatchHandledScreen<T extends ScreenHandler> extends Screen implemen
} }
@Unique
private Slot didBeforeSlotRender;
@WrapOperation( @WrapOperation(
method = "render", method = "drawSlots",
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
target = "Lnet/minecraft/util/collection/DefaultedList;get(I)Ljava/lang/Object;")) target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawSlot(Lnet/minecraft/client/gui/DrawContext;Lnet/minecraft/screen/slot/Slot;)V"))
private Object beforeSlotRender(DefaultedList instance, int index, Operation<Object> original, @Local(argsOnly = true) DrawContext context) { private void beforeSlotRender(HandledScreen instance, DrawContext context, Slot slot, Operation<Void> original) {
var slot = (Slot) original.call(instance, index);
if (override != null) { if (override != null) {
didBeforeSlotRender = slot;
override.beforeSlotRender(context, slot); override.beforeSlotRender(context, slot);
} }
return slot; original.call(instance, context, slot);
} if (override != null) {
override.afterSlotRender(context, slot);
@Inject(method = "render",
at = @At(value = "INVOKE", target = "Lnet/minecraft/util/collection/DefaultedList;size()I"))
private void afterSlotRender(DrawContext context, int mouseX, int mouseY, float delta, CallbackInfo ci) {
if (override != null && didBeforeSlotRender != null) {
override.afterSlotRender(context, didBeforeSlotRender);
didBeforeSlotRender = null;
} }
} }

View File

@@ -1,33 +1,35 @@
package moe.nea.firmament.mixins.custommodels; package moe.nea.firmament.mixins.custommodels;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import moe.nea.firmament.features.texturepack.BakedModelExtra; import moe.nea.firmament.features.texturepack.BakedModelExtra;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.world.World; import net.minecraft.item.ModelTransformationMode;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemRenderer.class) @Mixin(ItemRenderer.class)
public class ApplyHeadModelInItemRenderer { public class ApplyHeadModelInItemRenderer {
@WrapOperation(method = "renderItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;Lnet/minecraft/world/World;III)V", @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/ItemRenderer;getModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;I)Lnet/minecraft/client/render/model/BakedModel;")) at = @At("HEAD"))
private BakedModel applyHeadModel(ItemRenderer instance, ItemStack stack, World world, LivingEntity entity, int seed, Operation<BakedModel> original, private void applyHeadModel(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded,
@Local(argsOnly = true) ModelTransformationMode modelTransformationMode) { MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay,
var model = original.call(instance, stack, world, entity, seed); BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci,
if (modelTransformationMode == ModelTransformationMode.HEAD @Local(argsOnly = true) LocalRef<BakedModel> modelMut
&& model instanceof BakedModelExtra extra) { ) {
var extra = BakedModelExtra.cast(model);
if (transformationMode == ModelTransformationMode.HEAD && extra != null) {
var headModel = extra.getHeadModel_firmament(); var headModel = extra.getHeadModel_firmament();
if (headModel != null) { if (headModel != null) {
model = headModel; modelMut.set(headModel);
} }
} }
return model;
} }
} }

View File

@@ -8,6 +8,7 @@ import net.minecraft.client.render.model.BakedModel;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -18,12 +19,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public abstract class GlobalModelOverridePatch { public abstract class GlobalModelOverridePatch {
@Shadow @Shadow
public abstract ItemModels getModels(); @Final
private ItemModels models;
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true) @Inject(method = "getModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;I)Lnet/minecraft/client/render/model/BakedModel;", at = @At("HEAD"), cancellable = true)
private void overrideGlobalModel( private void overrideGlobalModel(
ItemStack stack, World world, LivingEntity entity, ItemStack stack, World world, LivingEntity entity,
int seed, CallbackInfoReturnable<BakedModel> cir) { int seed, CallbackInfoReturnable<BakedModel> cir) {
CustomGlobalTextures.replaceGlobalModel(this.getModels(), stack, cir); CustomGlobalTextures.replaceGlobalModel(this.models, stack, cir);
} }
} }

View File

@@ -0,0 +1,57 @@
package moe.nea.firmament.mixins.custommodels;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.features.texturepack.BakedModelExtra;
import net.minecraft.block.AbstractSkullBlock;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.ModelWithHead;
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(HeadFeatureRenderer.class)
public class HeadModelReplacerPatch<S extends LivingEntityRenderState, M extends EntityModel<S> & ModelWithHead> {
/**
* This class serves to disable the replacing of head models with the vanilla block model. Vanilla first selects loads
* the model containing the head model regularly in {@link LivingEntityRenderer#updateRenderState}, but then discards
* the model in {@link HeadFeatureRenderer#render(MatrixStack, VertexConsumerProvider, int, LivingEntityRenderState, float, float)}
* if it detects a skull block. This serves to disable that functionality if a head model override is present.
*/
@WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;getBlock()Lnet/minecraft/block/Block;"))
private Block replaceSkull(BlockItem instance, Operation<Block> original, @Local BakedModel bakedModel) {
var oldBlock = original.call(instance);
if (oldBlock instanceof AbstractSkullBlock) {
var extra = BakedModelExtra.cast(bakedModel);
if (extra != null && extra.getHeadModel_firmament() != null)
return Blocks.ENCHANTING_TABLE; // Any non skull block. Let's choose the enchanting table because it is very distinct.
}
return oldBlock;
}
/**
* We disable the has model override, since texture packs get precedent to server data.
*/
@WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/feature/ArmorFeatureRenderer;hasModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/entity/EquipmentSlot;)Z"))
private boolean replaceHasModel(ItemStack stack, EquipmentSlot slot, Operation<Boolean> original,
@Local BakedModel bakedModel) {
var extra = BakedModelExtra.cast(bakedModel);
if (extra != null && extra.getHeadModel_firmament() != null)
return false;
return original.call(stack, slot);
}
}

View File

@@ -5,28 +5,30 @@ import moe.nea.firmament.features.texturepack.TintOverrides;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemRenderer; import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ModelTransformationMode;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ItemRenderer.class) @Mixin(value = ItemRenderer.class, priority = 1010)
public class ItemRendererTintContextPatch { public class ItemRendererTintContextPatch {
@Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/BakedModel;getTransformation()Lnet/minecraft/client/render/model/json/ModelTransformation;"), allow = 1) at = @At(value = "HEAD"), allow = 1)
private void onStartRendering(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) { private void onStartRendering(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci) {
if (model instanceof BakedModelExtra extra) { var extra = BakedModelExtra.cast(model);
if (extra != null) {
TintOverrides.Companion.enter(extra.getTintOverrides_firmament()); TintOverrides.Companion.enter(extra.getTintOverrides_firmament());
} }
} }
@Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;ZF)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;pop()V"), allow = 1) at = @At("TAIL"), allow = 1)
private void onEndRendering(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) { private void onEndRendering(ItemStack stack, ModelTransformationMode transformationMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, boolean useInventoryModel, float z, CallbackInfo ci) {
if (model instanceof BakedModelExtra extra) { var extra = BakedModelExtra.cast(model);
if (extra != null) {
TintOverrides.Companion.exit(extra.getTintOverrides_firmament()); TintOverrides.Companion.exit(extra.getTintOverrides_firmament());
} }
} }

View File

@@ -1,11 +1,11 @@
package moe.nea.firmament.mixins.custommodels; package moe.nea.firmament.mixins.custommodels;
import com.google.gson.annotations.SerializedName;
import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.features.texturepack.BakedModelExtra; import moe.nea.firmament.features.texturepack.BakedModelExtra;
import moe.nea.firmament.features.texturepack.JsonUnbakedModelFirmExtra; import moe.nea.firmament.features.texturepack.JsonUnbakedModelFirmExtra;
import moe.nea.firmament.features.texturepack.TintOverrides; import moe.nea.firmament.features.texturepack.TintOverrides;
import moe.nea.firmament.util.ErrorUtil;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.Baker; import net.minecraft.client.render.model.Baker;
import net.minecraft.client.render.model.ModelRotation; import net.minecraft.client.render.model.ModelRotation;
@@ -18,15 +18,20 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Collection;
import java.util.Objects; import java.util.Objects;
@Mixin(JsonUnbakedModel.class) @Mixin(JsonUnbakedModel.class)
public class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra { public abstract class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra {
@Shadow @Shadow
@Nullable @Nullable
protected JsonUnbakedModel parent; protected JsonUnbakedModel parent;
@Shadow
public abstract String toString();
@Unique @Unique
@Nullable @Nullable
public Identifier headModel; public Identifier headModel;
@@ -67,31 +72,59 @@ public class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra {
return ((JsonUnbakedModelFirmExtra) this.parent).getHeadModel_firmament(); return ((JsonUnbakedModelFirmExtra) this.parent).getHeadModel_firmament();
} }
@ModifyReturnValue(method = "getModelDependencies", at = @At("RETURN")) @Inject(method = "resolve", at = @At("HEAD"))
private Collection<Identifier> addDependencies(Collection<Identifier> original) { private void addDependencies(UnbakedModel.Resolver resolver, CallbackInfo ci) {
var headModel = getHeadModel_firmament(); var headModel = getHeadModel_firmament();
if (headModel != null) { if (headModel != null) {
original.add(headModel); resolver.resolve(headModel);
}
}
private void addExtraBakeInfo(BakedModel bakedModel, Baker baker) {
if (!this.toString().contains("minecraft") && this.toString().contains("crimson")) {
System.out.println("Found non minecraft model " + this);
}
var extra = BakedModelExtra.cast(bakedModel);
if (extra != null) {
var headModel = getHeadModel_firmament();
if (headModel != null) {
extra.setHeadModel_firmament(baker.bake(headModel, ModelRotation.X0_Y0));
}
if (getTintOverrides_firmament().hasOverrides()) {
extra.setTintOverrides_firmament(getTintOverrides_firmament());
}
}
}
/**
* @see ProvideBakerToJsonUnbakedModelPatch
*/
@Override
public void storeExtraBaker_firmament(@NotNull Baker baker) {
this.storedBaker = baker;
}
@Unique
private Baker storedBaker;
@ModifyReturnValue(
method = "bake(Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;",
at = @At("RETURN"))
private BakedModel bakeExtraInfoWithoutBaker(BakedModel original) {
if (storedBaker != null) {
addExtraBakeInfo(original, storedBaker);
storedBaker = null;
} }
return original; return original;
} }
@ModifyReturnValue( @ModifyReturnValue(
method = "bake(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;", method = {
"bake(Lnet/minecraft/client/render/model/Baker;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;"
},
at = @At(value = "RETURN")) at = @At(value = "RETURN"))
private BakedModel bakeExtraInfo(BakedModel original, @Local(argsOnly = true) Baker baker) { private BakedModel bakeExtraInfo(BakedModel original, @Local(argsOnly = true) Baker baker) {
if (original instanceof BakedModelExtra extra) { addExtraBakeInfo(original, baker);
var headModel = getHeadModel_firmament();
if (headModel != null) {
UnbakedModel unbakedModel = baker.getOrLoadModel(headModel);
extra.setHeadModel_firmament(
Objects.equals(unbakedModel, parent)
? null
: baker.bake(headModel, ModelRotation.X0_Y0));
}
if (getTintOverrides_firmament().hasOverrides())
extra.setTintOverrides_firmament(getTintOverrides_firmament());
}
return original; return original;
} }
} }

View File

@@ -6,26 +6,24 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local; import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.features.texturepack.CustomGlobalArmorOverrides; import moe.nea.firmament.features.texturepack.CustomGlobalArmorOverrides;
import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer; import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
import net.minecraft.item.ArmorMaterial; import net.minecraft.component.type.EquippableComponent;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import java.util.List; import java.util.Optional;
@Mixin(ArmorFeatureRenderer.class) @Mixin(ArmorFeatureRenderer.class)
public class PatchArmorTexture { public class PatchArmorTexture {
@WrapOperation( @WrapOperation(
method = "renderArmor", method = "renderArmor",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ArmorMaterial;layers()Ljava/util/List;")) at = @At(value = "INVOKE", target = "Lnet/minecraft/component/type/EquippableComponent;model()Ljava/util/Optional;"))
private List<ArmorMaterial.Layer> overrideLayers( private Optional<Identifier> overrideLayers(
ArmorMaterial instance, EquippableComponent instance, Operation<Optional<Identifier>> original, @Local(argsOnly = true) ItemStack itemStack
Operation<List<ArmorMaterial.Layer>> original,
@Local ItemStack itemStack
) { ) {
// TODO: check that all armour items are naturally equippable and have the equppable component. otherwise our call here will not be reached.
var overrides = CustomGlobalArmorOverrides.overrideArmor(itemStack); var overrides = CustomGlobalArmorOverrides.overrideArmor(itemStack);
if (overrides == null) return overrides.or(() -> original.call(instance));
return original.call(instance);
return overrides;
} }
} }

View File

@@ -1,45 +0,0 @@
package moe.nea.firmament.mixins.custommodels;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.features.texturepack.BakedModelExtra;
import net.minecraft.block.AbstractSkullBlock;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.item.HeldItemRenderer;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(HeadFeatureRenderer.class)
public class PatchHeadFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> {
@Shadow
@Final
private HeldItemRenderer heldItemRenderer;
@WrapOperation(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/entity/LivingEntity;FFFFFF)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;getBlock()Lnet/minecraft/block/Block;"))
private Block replaceSkull(BlockItem instance, Operation<Block> original, @Local ItemStack itemStack, @Local(argsOnly = true) T entity) {
var oldBlock = original.call(instance);
if (oldBlock instanceof AbstractSkullBlock) {
var bakedModel = this.heldItemRenderer.itemRenderer
.getModel(itemStack, entity.getWorld(), entity, 0);
if (bakedModel instanceof BakedModelExtra extra && extra.getHeadModel_firmament() != null)
return Blocks.ENCHANTING_TABLE; // Any non skull block. Let's choose the enchanting table because it is very distinct.
}
return oldBlock;
}
}

View File

@@ -0,0 +1,22 @@
package moe.nea.firmament.mixins.custommodels;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import moe.nea.firmament.features.texturepack.CustomGlobalArmorOverrides;
import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
import net.minecraft.client.render.entity.equipment.EquipmentRenderer;
import net.minecraft.item.equipment.EquipmentModel;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(EquipmentRenderer.class)
public class PatchLegacyArmorLayerSupport {
@WrapOperation(method = "render(Lnet/minecraft/item/equipment/EquipmentModel$LayerType;Lnet/minecraft/util/Identifier;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/equipment/EquipmentModelLoader;get(Lnet/minecraft/util/Identifier;)Lnet/minecraft/item/equipment/EquipmentModel;"))
private EquipmentModel patchModelLayers(EquipmentModelLoader instance, Identifier id, Operation<EquipmentModel> original) {
var modelOverride = CustomGlobalArmorOverrides.overrideArmorLayer(id);
if (modelOverride != null) return modelOverride;
return original.call(instance, id);
}
}

View File

@@ -26,7 +26,7 @@ public class PatchOverrideDeserializer {
method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/ModelOverride;", method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/ModelOverride;",
at = @At(value = "RETURN")) at = @At(value = "RETURN"))
private ModelOverride addCustomOverrides(ModelOverride original, @Local JsonObject jsonObject) { private ModelOverride addCustomOverrides(ModelOverride original, @Local JsonObject jsonObject) {
var originalData = (ModelOverrideData) original; var originalData = (ModelOverrideData) (Object) original;
originalData.setFirmamentOverrides(CustomModelOverrideParser.parseCustomModelOverrides(jsonObject)); originalData.setFirmamentOverrides(CustomModelOverrideParser.parseCustomModelOverrides(jsonObject));
return original; return original;
} }

View File

@@ -0,0 +1,27 @@
package moe.nea.firmament.mixins.custommodels;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import moe.nea.firmament.features.texturepack.JsonUnbakedModelFirmExtra;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.Baker;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.SpriteIdentifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import java.util.function.Function;
/**
* @see JsonUnbakedModelDataHolder#storeExtraBaker_firmament
*/
@Mixin(targets = "net.minecraft.client.render.model.ModelBaker$BakerImpl")
public abstract class ProvideBakerToJsonUnbakedModelPatch implements Baker {
@WrapOperation(method = "bake(Lnet/minecraft/client/render/model/UnbakedModel;Lnet/minecraft/client/render/model/ModelBakeSettings;)Lnet/minecraft/client/render/model/BakedModel;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/JsonUnbakedModel;bake(Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;"))
private BakedModel provideExtraBakerToModel(JsonUnbakedModel instance, Function<SpriteIdentifier, Sprite> function, ModelBakeSettings modelBakeSettings, boolean bl, Operation<BakedModel> original) {
((JsonUnbakedModelFirmExtra) instance).storeExtraBaker_firmament(this);
return original.call(instance, function, modelBakeSettings, bl);
}
}

View File

@@ -0,0 +1,37 @@
package moe.nea.firmament.mixins.custommodels;
import moe.nea.firmament.events.BakeExtraModelsEvent;
import net.minecraft.client.render.model.BlockStatesLoader;
import net.minecraft.client.render.model.ItemModel;
import net.minecraft.client.render.model.ReferencedModelsCollector;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(ReferencedModelsCollector.class)
public abstract class ReferenceCustomModelsPatch {
@Shadow
protected abstract void addTopLevelModel(ModelIdentifier modelId, UnbakedModel model);
@Shadow
@Final
private Map<Identifier, UnbakedModel> inputs;
@Inject(method = "addBlockStates", at = @At("RETURN"))
private void addFirmamentReferencedModels(
BlockStatesLoader.BlockStateDefinition definition, CallbackInfo ci
) {
inputs.keySet().stream().filter(it->it.toString().contains("firm")).forEach(System.out::println);
BakeExtraModelsEvent.Companion.publish(new BakeExtraModelsEvent(
(modelIdentifier, identifier) -> addTopLevelModel(modelIdentifier, new ItemModel(identifier))));
}
}

View File

@@ -17,7 +17,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(ModelOverrideList.class) @Mixin(ModelOverrideList.class)
public class TestForFirmamentOverridePredicatesPatch { public class TestForFirmamentOverridePredicatesPatch {
@ModifyArg(method = "<init>(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/List;)V", @ModifyArg(method = "<init>(Lnet/minecraft/client/render/model/Baker;Ljava/util/List;)V",
at = @At( at = @At(
value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z" value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z"
)) ))
@@ -26,17 +26,17 @@ public class TestForFirmamentOverridePredicatesPatch {
@Local ModelOverride modelOverride @Local ModelOverride modelOverride
) { ) {
var bakedOverride = (ModelOverrideList.BakedOverride) element; var bakedOverride = (ModelOverrideList.BakedOverride) element;
((BakedOverrideData) bakedOverride) ((BakedOverrideData) (Object) bakedOverride)
.setFirmamentOverrides(((ModelOverrideData) modelOverride).getFirmamentOverrides()); .setFirmamentOverrides(((ModelOverrideData) (Object) modelOverride).getFirmamentOverrides());
return element; return element;
} }
@ModifyExpressionValue(method = "apply", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;test([F)Z")) @ModifyExpressionValue(method = "getModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;test([F)Z"))
public boolean testFirmamentOverrides(boolean originalValue, public boolean testFirmamentOverrides(boolean originalValue,
@Local ModelOverrideList.BakedOverride bakedOverride, @Local ModelOverrideList.BakedOverride bakedOverride,
@Local(argsOnly = true) ItemStack stack) { @Local(argsOnly = true) ItemStack stack) {
if (!originalValue) return false; if (!originalValue) return false;
var overrideData = (BakedOverrideData) bakedOverride; var overrideData = (BakedOverrideData) (Object) bakedOverride;
var overrides = overrideData.getFirmamentOverrides(); var overrides = overrideData.getFirmamentOverrides();
if (overrides == null) return true; if (overrides == null) return true;
if (!CustomSkyBlockTextures.TConfig.INSTANCE.getEnableModelOverrides()) return false; if (!CustomSkyBlockTextures.TConfig.INSTANCE.getEnableModelOverrides()) return false;

View File

@@ -1,20 +1,23 @@
package moe.nea.firmament.events 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.client.util.ModelIdentifier
import net.minecraft.util.Identifier
// TODO: Rename this event, since it is not really directly baking models anymore
class BakeExtraModelsEvent( class BakeExtraModelsEvent(
private val addItemModel: Consumer<ModelIdentifier>, private val addAnyModel: BiConsumer<ModelIdentifier, Identifier>,
private val addAnyModel: Consumer<ModelIdentifier>,
) : FirmamentEvent() { ) : FirmamentEvent() {
fun addNonItemModel(modelIdentifier: ModelIdentifier) { fun addNonItemModel(modelIdentifier: ModelIdentifier, identifier: Identifier) {
this.addAnyModel.accept(modelIdentifier) this.addAnyModel.accept(modelIdentifier, identifier)
} }
fun addItemModel(modelIdentifier: ModelIdentifier) { fun addItemModel(modelIdentifier: ModelIdentifier) {
this.addItemModel.accept(modelIdentifier) addNonItemModel(
modelIdentifier,
modelIdentifier.id.withPrefixedPath(ReferencedModelsCollector.ITEM_DIRECTORY))
} }
companion object : FirmamentEventBus<BakeExtraModelsEvent>() companion object : FirmamentEventBus<BakeExtraModelsEvent>()

View File

@@ -2,10 +2,11 @@ package moe.nea.firmament.events
import java.util.Optional import java.util.Optional
import kotlin.jvm.optionals.getOrNull 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.BakedModel
import net.minecraft.client.render.model.BakedModelManager
import net.minecraft.client.util.ModelIdentifier import net.minecraft.client.util.ModelIdentifier
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import moe.nea.firmament.util.ErrorUtil
import moe.nea.firmament.util.collections.WeakCache import moe.nea.firmament.util.collections.WeakCache
data class CustomItemModelEvent( data class CustomItemModelEvent(
@@ -14,10 +15,11 @@ data class CustomItemModelEvent(
) : FirmamentEvent() { ) : FirmamentEvent() {
companion object : FirmamentEventBus<CustomItemModelEvent>() { companion object : FirmamentEventBus<CustomItemModelEvent>() {
val cache = val cache =
WeakCache.memoize<ItemStack, BakedModelManager, Optional<BakedModel>>("CustomItemModels") { stack, models -> WeakCache.memoize<ItemStack, ItemModels, Optional<BakedModel>>("CustomItemModels") { stack, models ->
val modelId = getModelIdentifier(stack) ?: return@memoize Optional.empty() val modelId = getModelIdentifier(stack) ?: return@memoize Optional.empty()
val bakedModel = models.getModel(modelId) ErrorUtil.softCheck("Model Id needs to have an inventory variant", modelId.variant() == "inventory")
if (bakedModel === models.missingModel) return@memoize Optional.empty() val bakedModel = models.getModel(modelId.id)
if (bakedModel == null || bakedModel === models.missingModelSupplier.get()) return@memoize Optional.empty()
Optional.of(bakedModel) Optional.of(bakedModel)
} }
@@ -28,7 +30,7 @@ data class CustomItemModelEvent(
} }
@JvmStatic @JvmStatic
fun getModel(itemStack: ItemStack?, thing: BakedModelManager): BakedModel? { fun getModel(itemStack: ItemStack?, thing: ItemModels): BakedModel? {
if (itemStack == null) return null if (itemStack == null) return null
return cache.invoke(itemStack, thing).getOrNull() return cache.invoke(itemStack, thing).getOrNull()
} }

View File

@@ -0,0 +1,9 @@
package moe.nea.firmament.events
/**
* Called in a devenv after minecraft has been initialized. This event should be used to force instantiation of lazy
* variables (and similar late init) to cause any possible issues to materialize.
*/
class DebugInstantiateEvent : FirmamentEvent() {
companion object : FirmamentEventBus<DebugInstantiateEvent>()
}

View File

@@ -5,7 +5,6 @@ import java.util.concurrent.Executor
import net.minecraft.resource.ReloadableResourceManagerImpl import net.minecraft.resource.ReloadableResourceManagerImpl
import net.minecraft.resource.ResourceManager import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceReloader import net.minecraft.resource.ResourceReloader
import net.minecraft.util.profiler.Profiler
data class FinalizeResourceManagerEvent( data class FinalizeResourceManagerEvent(
val resourceManager: ReloadableResourceManagerImpl, val resourceManager: ReloadableResourceManagerImpl,
@@ -16,10 +15,8 @@ data class FinalizeResourceManagerEvent(
resourceManager.registerReloader(object : ResourceReloader { resourceManager.registerReloader(object : ResourceReloader {
override fun reload( override fun reload(
synchronizer: ResourceReloader.Synchronizer, synchronizer: ResourceReloader.Synchronizer,
manager: ResourceManager?, manager: ResourceManager,
prepareProfiler: Profiler?, prepareExecutor: Executor,
applyProfiler: Profiler?,
prepareExecutor: Executor?,
applyExecutor: Executor applyExecutor: Executor
): CompletableFuture<Void> { ): CompletableFuture<Void> {
return CompletableFuture.completedFuture(Unit) return CompletableFuture.completedFuture(Unit)

View File

@@ -37,7 +37,7 @@ data class IsSlotProtectedEvent(
val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride) val event = IsSlotProtectedEvent(slot, action, false, itemStackOverride)
publish(event) publish(event)
if (event.isProtected && !event.silent) { 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() CommonSoundEffects.playFailure()
} }
return event.isProtected return event.isProtected

View File

@@ -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)
}
}
}

View File

@@ -3,20 +3,19 @@
package moe.nea.firmament.events package moe.nea.firmament.events
import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.DrawContext
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.texture.Sprite import net.minecraft.client.texture.Sprite
import net.minecraft.screen.slot.Slot import net.minecraft.screen.slot.Slot
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.render.drawGuiTexture
interface SlotRenderEvents { interface SlotRenderEvents {
val context: DrawContext val context: DrawContext
val slot: Slot val slot: Slot
val mouseX: Int
val mouseY: Int
val delta: Float
fun highlight(sprite: Sprite) { fun highlight(sprite: Identifier) {
context.drawSprite( context.drawGuiTexture(
slot.x, slot.y, 0, 16, 16, slot.x, slot.y, 0, 16, 16,
sprite sprite
) )
@@ -24,9 +23,6 @@ interface SlotRenderEvents {
data class Before( data class Before(
override val context: DrawContext, override val slot: Slot, override val context: DrawContext, override val slot: Slot,
override val mouseX: Int,
override val mouseY: Int,
override val delta: Float
) : FirmamentEvent(), ) : FirmamentEvent(),
SlotRenderEvents { SlotRenderEvents {
companion object : FirmamentEventBus<Before>() companion object : FirmamentEventBus<Before>()
@@ -34,9 +30,6 @@ interface SlotRenderEvents {
data class After( data class After(
override val context: DrawContext, override val slot: Slot, override val context: DrawContext, override val slot: Slot,
override val mouseX: Int,
override val mouseY: Int,
override val delta: Float
) : FirmamentEvent(), ) : FirmamentEvent(),
SlotRenderEvents { SlotRenderEvents {
companion object : FirmamentEventBus<After>() companion object : FirmamentEventBus<After>()

View File

@@ -1,7 +1,10 @@
package moe.nea.firmament.events package moe.nea.firmament.events
class WorldReadyEvent : FirmamentEvent() { class WorldReadyEvent : FirmamentEvent() {
companion object : FirmamentEventBus<WorldReadyEvent>() companion object : FirmamentEventBus<WorldReadyEvent>()
// class FullyLoaded : FirmamentEvent() {
// companion object : FirmamentEventBus<FullyLoaded>() {
// TODO: check WorldLoadingState
// }
// }
} }

View File

@@ -17,10 +17,7 @@ import net.minecraft.util.math.Vec3d
data class WorldRenderLastEvent( data class WorldRenderLastEvent(
val matrices: MatrixStack, val matrices: MatrixStack,
val tickCounter: RenderTickCounter, val tickCounter: RenderTickCounter,
val renderBlockOutline: Boolean,
val camera: Camera, val camera: Camera,
val gameRenderer: GameRenderer,
val lightmapTextureManager: LightmapTextureManager,
val vertexConsumers: VertexConsumerProvider.Immediate, val vertexConsumers: VertexConsumerProvider.Immediate,
) : FirmamentEvent() { ) : FirmamentEvent() {
companion object : FirmamentEventBus<WorldRenderLastEvent>() companion object : FirmamentEventBus<WorldRenderLastEvent>()

View File

@@ -13,8 +13,10 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlin.math.min import kotlin.math.min
import net.minecraft.client.gui.screen.ChatScreen import net.minecraft.client.gui.screen.ChatScreen
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.texture.NativeImage import net.minecraft.client.texture.NativeImage
import net.minecraft.client.texture.NativeImageBackedTexture import net.minecraft.client.texture.NativeImageBackedTexture
import net.minecraft.scoreboard.ScoreboardCriterion.RenderType
import net.minecraft.text.ClickEvent import net.minecraft.text.ClickEvent
import net.minecraft.text.HoverEvent import net.minecraft.text.HoverEvent
import net.minecraft.text.Style 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.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.render.drawTexture
import moe.nea.firmament.util.transformEachRecursively import moe.nea.firmament.util.transformEachRecursively
import moe.nea.firmament.util.unformattedString import moe.nea.firmament.util.unformattedString

View File

@@ -37,10 +37,10 @@ object DeveloperFeatures : FirmamentFeature {
builder.directory(gradleDir.toFile()) builder.directory(gradleDir.toFile())
builder.inheritIO() builder.inheritIO()
val process = builder.start() 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() val startTime = TimeMark.now()
process.toHandle().onExit().thenApply { process.toHandle().onExit().thenApply {
MC.player?.sendMessage(Text.stringifiedTranslatable( MC.sendChat(Text.stringifiedTranslatable(
"firmament.dev.resourcerebuild.done", "firmament.dev.resourcerebuild.done",
startTime.passedTime())) startTime.passedTime()))
Unit Unit

View File

@@ -9,6 +9,7 @@ import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity import net.minecraft.entity.LivingEntity
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.Items import net.minecraft.item.Items
import net.minecraft.nbt.NbtOps
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.text.TextCodecs import net.minecraft.text.TextCodecs
import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.hit.BlockHitResult
@@ -54,15 +55,13 @@ object PowerUserTools : FirmamentFeature {
var lastCopiedStack: Pair<ItemStack, Text>? = null var lastCopiedStack: Pair<ItemStack, Text>? = null
set(value) { set(value) {
field = value field = value
if (value != null) if (value != null) lastCopiedStackViewTime = true
lastCopiedStackViewTime = true
} }
var lastCopiedStackViewTime = false var lastCopiedStackViewTime = false
@Subscribe @Subscribe
fun resetLastCopiedStack(event: TickEvent) { fun resetLastCopiedStack(event: TickEvent) {
if (!lastCopiedStackViewTime) if (!lastCopiedStackViewTime) lastCopiedStack = null
lastCopiedStack = null
lastCopiedStackViewTime = false lastCopiedStackViewTime = false
} }
@@ -154,13 +153,13 @@ object PowerUserTools : FirmamentFeature {
} }
ClipboardUtils.setTextContent(skullTexture.toString()) ClipboardUtils.setTextContent(skullTexture.toString())
lastCopiedStack = lastCopiedStack =
Pair( Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString()))
item,
Text.stringifiedTranslatable("firmament.tooltip.copied.skull-id", skullTexture.toString())
)
println("Copied skull id: $skullTexture") println("Copied skull id: $skullTexture")
} else if (it.matches(TConfig.copyItemStack)) { } 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")) lastCopiedStack = Pair(item, Text.stringifiedTranslatable("firmament.tooltip.copied.stack"))
} }
} }

View File

@@ -104,12 +104,13 @@ object AncestralSpadeSolver : SubscriptionOwner {
if (!isEnabled()) return if (!isEnabled()) return
RenderInWorldContext.renderInWorld(event) { RenderInWorldContext.renderInWorld(event) {
nextGuess?.let { nextGuess?.let {
color(1f, 1f, 0f, 0.5f) tinyBlock(it, 1f, 0x80FFFFFF.toInt())
tinyBlock(it, 1f) // TODO: replace this
color(1f, 1f, 0f, 1f) color(1f, 1f, 0f, 1f)
tracer(it, lineWidth = 3f) tracer(it, lineWidth = 3f)
} }
if (particlePositions.size > 2 && lastDing.passedTime() < 10.seconds && nextGuess != null) { if (particlePositions.size > 2 && lastDing.passedTime() < 10.seconds && nextGuess != null) {
// TODO: replace this // TODO: add toggle
color(0f, 1f, 0f, 0.7f) color(0f, 1f, 0f, 0.7f)
line(particlePositions) line(particlePositions)
} }

View File

@@ -1,6 +1,6 @@
package moe.nea.firmament.features.diana package moe.nea.firmament.features.diana
import me.shedaniel.math.Color
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import net.minecraft.particle.ParticleTypes import net.minecraft.particle.ParticleTypes
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
@@ -111,12 +111,12 @@ object NearbyBurrowsSolver : SubscriptionOwner {
if (!DianaWaypoints.TConfig.nearbyWaypoints) return if (!DianaWaypoints.TConfig.nearbyWaypoints) return
renderInWorld(event) { renderInWorld(event) {
for ((location, burrow) in burrows) { for ((location, burrow) in burrows) {
when (burrow) { val color = when (burrow) {
BurrowType.START -> color(.2f, .8f, .2f, 0.4f) BurrowType.START -> Color.ofRGBA(.2f, .8f, .2f, 0.4f)
BurrowType.MOB -> color(0.3f, 0.4f, 0.9f, 0.4f) BurrowType.MOB -> Color.ofRGBA(0.3f, 0.4f, 0.9f, 0.4f)
BurrowType.TREASURE -> color(1f, 0.7f, 0.2f, 0.4f) BurrowType.TREASURE -> Color.ofRGBA(1f, 0.7f, 0.2f, 0.4f)
} }
block(location) block(location, color.color)
} }
} }
} }

View File

@@ -69,7 +69,7 @@ object CraftingOverlay : FirmamentFeature {
if (!slot.hasStack()) { if (!slot.hasStack()) {
val itemStack = SBItemStack(expectedItem)?.asImmutableItemStack() ?: return val itemStack = SBItemStack(expectedItem)?.asImmutableItemStack() ?: return
event.context.drawItem(itemStack, event.slot.x, event.slot.y) event.context.drawItem(itemStack, event.slot.x, event.slot.y)
event.context.drawItemInSlot( event.context.drawStackOverlay(
MC.font, MC.font,
itemStack, itemStack,
event.slot.x, event.slot.x,

View File

@@ -4,6 +4,7 @@ package moe.nea.firmament.features.inventory
import java.awt.Color import java.awt.Color
import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.DrawContext
import net.minecraft.client.render.RenderLayer
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.util.Formatting import net.minecraft.util.Formatting
import net.minecraft.util.Identifier 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.mc.loreAccordingToNbt
import moe.nea.firmament.util.collections.lastNotNullOfOrNull import moe.nea.firmament.util.collections.lastNotNullOfOrNull
import moe.nea.firmament.util.collections.memoizeIdentity import moe.nea.firmament.util.collections.memoizeIdentity
import moe.nea.firmament.util.render.drawGuiTexture
import moe.nea.firmament.util.unformattedString import moe.nea.firmament.util.unformattedString
object ItemRarityCosmetics : FirmamentFeature { object ItemRarityCosmetics : FirmamentFeature {
@@ -43,10 +45,10 @@ object ItemRarityCosmetics : FirmamentFeature {
"SUPREME" to Formatting.DARK_RED, "SUPREME" to Formatting.DARK_RED,
).mapValues { ).mapValues {
val c = Color(it.value.colorValue!!) 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 { return itemStack.loreAccordingToNbt.lastNotNullOfOrNull {
val entry = it.unformattedString val entry = it.unformattedString
rarityToColor.entries.find { (k, v) -> k in entry }?.value 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) { fun drawItemStackRarity(drawContext: DrawContext, x: Int, y: Int, item: ItemStack) {
val (r, g, b) = getSkyblockRarity(item) ?: return val rgb = getSkyblockRarity(item) ?: return
drawContext.drawSprite( drawContext.drawGuiTexture(
RenderLayer::getGuiTextured,
Identifier.of("firmament:item_rarity_background"),
x, y, x, y,
0,
16, 16, 16, 16,
MC.guiAtlasManager.getSprite(Identifier.of("firmament:item_rarity_background")), rgb
r, g, b, 1F
) )
} }

View File

@@ -7,6 +7,7 @@ import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.petData import moe.nea.firmament.util.petData
import moe.nea.firmament.util.render.drawGuiTexture
import moe.nea.firmament.util.useMatch import moe.nea.firmament.util.useMatch
object PetFeatures : FirmamentFeature { object PetFeatures : FirmamentFeature {
@@ -28,9 +29,9 @@ object PetFeatures : FirmamentFeature {
val stack = event.slot.stack val stack = event.slot.stack
if (stack.petData?.active == true) if (stack.petData?.active == true)
petMenuTitle.useMatch(MC.screenName ?: return) { petMenuTitle.useMatch(MC.screenName ?: return) {
event.context.drawSprite( event.context.drawGuiTexture(
event.slot.x, event.slot.y, 0, 16, 16, event.slot.x, event.slot.y, 0, 16, 16,
MC.guiAtlasManager.getSprite(Identifier.of("firmament:selected_pet_background")) Identifier.of("firmament:selected_pet_background")
) )
} }
} }

View File

@@ -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.SlotUtils.swapWithHotBar
import moe.nea.firmament.util.mc.displayNameAccordingToNbt import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.render.GuiRenderLayers
import moe.nea.firmament.util.render.drawLine import moe.nea.firmament.util.render.drawLine
import moe.nea.firmament.util.skyblockUUID import moe.nea.firmament.util.skyblockUUID
import moe.nea.firmament.util.unformattedString import moe.nea.firmament.util.unformattedString
@@ -211,6 +212,11 @@ object SlotLocking : FirmamentFeature {
} }
if (it.matches(TConfig.slotBind)) { if (it.matches(TConfig.slotBind)) {
storedLockingSlot = null storedLockingSlot = null
val boundSlots = DConfig.data?.boundSlots ?: return
if (slot != null)
boundSlots.entries.removeIf {
it.value == slot.index || it.key == slot.index
}
} }
} }
@@ -331,11 +337,8 @@ object SlotLocking : FirmamentFeature {
val isSlotLocked = it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf()) val isSlotLocked = it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())
val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf()) val isUUIDLocked = (it.slot.stack?.skyblockUUID) in (lockedUUIDs ?: setOf())
if (isSlotLocked || isUUIDLocked) { if (isSlotLocked || isUUIDLocked) {
RenderSystem.disableDepthTest() it.context.drawGuiTexture(
it.context.drawSprite( GuiRenderLayers.GUI_TEXTURED_NO_DEPTH,
it.slot.x, it.slot.y, 0,
16, 16,
MC.guiAtlasManager.getSprite(
when { when {
isSlotLocked -> isSlotLocked ->
(Identifier.of("firmament:slot_locked")) (Identifier.of("firmament:slot_locked"))
@@ -345,10 +348,11 @@ object SlotLocking : FirmamentFeature {
else -> else ->
error("unreachable") error("unreachable")
} },
it.slot.x, it.slot.y,
16, 16,
-1
) )
)
RenderSystem.enableDepthTest()
} }
} }
} }

View File

@@ -18,6 +18,7 @@ import moe.nea.firmament.repo.RepoManager
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.collections.memoize import moe.nea.firmament.util.collections.memoize
import moe.nea.firmament.util.render.drawGuiTexture
@Serializable @Serializable
data class InventoryButton( data class InventoryButton(
@@ -54,13 +55,13 @@ data class InventoryButton(
} }
fun render(context: DrawContext) { fun render(context: DrawContext) {
context.drawSprite( context.drawGuiTexture(
0, 0,
0, 0,
0, 0,
dimensions.width, dimensions.width,
dimensions.height, dimensions.height,
MC.guiAtlasManager.getSprite(Identifier.of("firmament:inventory_button_background")) Identifier.of("firmament:inventory_button_background")
) )
context.drawItem(getItem(), 1, 1) context.drawItem(getItem(), 1, 1)
} }

View File

@@ -84,7 +84,6 @@ class InventoryButtonEditor(
context.matrices.push() context.matrices.push()
context.matrices.translate(0f, 0f, -10f) context.matrices.translate(0f, 0f, -10f)
context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1) context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1)
context.setShaderColor(1f, 1f, 1f, 1f)
context.matrices.pop() context.matrices.pop()
for (button in buttons) { for (button in buttons) {
val buttonPosition = button.getBounds(lastGuiRect) val buttonPosition = button.getBounds(lastGuiRect)

View File

@@ -40,6 +40,7 @@ sealed interface StorageBackingHandle {
* representable as a [StorageBackingHandle], meaning another screen is open, for example the enderchest icon * representable as a [StorageBackingHandle], meaning another screen is open, for example the enderchest icon
* selection screen. * selection screen.
*/ */
@OptIn(ExperimentalContracts::class)
fun fromScreen(screen: Screen?): StorageBackingHandle? { fun fromScreen(screen: Screen?): StorageBackingHandle? {
contract { contract {
returnsNotNull() implies (screen != null) returnsNotNull() implies (screen != null)

View File

@@ -21,6 +21,7 @@ import moe.nea.firmament.util.MoulConfigUtils.clickMCComponentInPlace
import moe.nea.firmament.util.MoulConfigUtils.drawMCComponentInPlace import moe.nea.firmament.util.MoulConfigUtils.drawMCComponentInPlace
import moe.nea.firmament.util.assertTrueOr import moe.nea.firmament.util.assertTrueOr
import moe.nea.firmament.util.customgui.customGui import moe.nea.firmament.util.customgui.customGui
import moe.nea.firmament.util.render.drawGuiTexture
class StorageOverlayScreen : Screen(Text.literal("")) { class StorageOverlayScreen : Screen(Text.literal("")) {
@@ -162,13 +163,11 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
context.drawGuiTexture(upperBackgroundSprite, context.drawGuiTexture(upperBackgroundSprite,
measurements.x, measurements.x,
measurements.y, measurements.y,
0,
measurements.overviewWidth, measurements.overviewWidth,
measurements.overviewHeight) measurements.overviewHeight)
context.drawGuiTexture(playerInventorySprite, context.drawGuiTexture(playerInventorySprite,
measurements.playerX, measurements.playerX,
measurements.playerY, measurements.playerY,
0,
PLAYER_WIDTH, PLAYER_WIDTH,
PLAYER_HEIGHT) PLAYER_HEIGHT)
} }
@@ -188,7 +187,7 @@ class StorageOverlayScreen : Screen(Text.literal("")) {
items.withIndex().forEach { (index, item) -> items.withIndex().forEach { (index, item) ->
val (x, y) = getPlayerInventorySlotPosition(index) val (x, y) = getPlayerInventorySlotPosition(index)
context.drawItem(item, x, y, 0) 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 val slotY = (index / 9) * SLOT_SIZE + y + 4 + textRenderer.fontHeight + 1
if (slots == null) { if (slots == null) {
context.drawItem(stack, slotX, slotY) context.drawItem(stack, slotX, slotY)
context.drawItemInSlot(textRenderer, stack, slotX, slotY) context.drawStackOverlay(textRenderer, stack, slotX, slotY)
} else { } else {
val slot = slots[index] val slot = slots[index]
slot.x = slotX - slotOffset.x slot.x = slotX - slotOffset.x

View File

@@ -111,7 +111,7 @@ class StorageOverviewScreen() : Screen(Text.empty()) {
context.fill(x, y, x + 18, y + 18, 0x40808080.toInt()) context.fill(x, y, x + 18, y + 18, 0x40808080.toInt())
} }
context.drawItem(stack, x + 1, y + 1) 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)
} }
} }

View File

@@ -1,6 +1,6 @@
package moe.nea.firmament.features.mining 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.annotations.Subscribe
import moe.nea.firmament.events.SlotRenderEvents import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
@@ -19,10 +19,8 @@ object CommissionFeatures {
if (!Config.highlightCompletedCommissions) return if (!Config.highlightCompletedCommissions) return
if (MC.screenName != "Commissions") return if (MC.screenName != "Commissions") return
val stack = event.slot.stack val stack = event.slot.stack
if(stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) { if (stack.loreAccordingToNbt.any { it.unformattedString == "COMPLETED" }) {
event.highlight( event.highlight(Firmament.identifier("completed_commission_background"))
MC.guiAtlasManager.getSprite(Identifier.of("firmament:completed_commission_background"))
)
} }
} }
} }

View File

@@ -9,9 +9,7 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.entity.player.PlayerInventory import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.Items import net.minecraft.item.Items
import net.minecraft.screen.GenericContainerScreenHandler import net.minecraft.screen.GenericContainerScreenHandler
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.slot.Slot import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe 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.CommonTextures
import moe.nea.firmament.util.mc.SlotUtils.clickRightMouseButton import moe.nea.firmament.util.mc.SlotUtils.clickRightMouseButton
import moe.nea.firmament.util.mc.displayNameAccordingToNbt 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.unformattedString
import moe.nea.firmament.util.useMatch import moe.nea.firmament.util.useMatch
@@ -81,7 +80,7 @@ object HotmPresets {
override fun render(drawContext: DrawContext, delta: Float, mouseX: Int, mouseY: Int) { override fun render(drawContext: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
drawContext.drawGuiTexture( drawContext.drawGuiTexture(
CommonTextures.genericWidget(), CommonTextures.genericWidget(),
bounds.x, bounds.y, 0, bounds.x, bounds.y,
bounds.width, bounds.width,
bounds.height, bounds.height,
) )
@@ -191,7 +190,7 @@ object HotmPresets {
if (hotmInventoryName == MC.screenName if (hotmInventoryName == MC.screenName
&& event.slot.stack.displayNameAccordingToNbt.unformattedString in highlightedPerks && event.slot.stack.displayNameAccordingToNbt.unformattedString in highlightedPerks
) { ) {
event.highlight(MC.guiAtlasManager.getSprite(Firmament.identifier("hotm_perk_preset"))) event.highlight((Firmament.identifier("hotm_perk_preset")))
} }
} }

View File

@@ -1,9 +1,28 @@
package moe.nea.firmament.features.texturepack package moe.nea.firmament.features.texturepack
import net.fabricmc.fabric.api.renderer.v1.model.WrapperBakedModel as WrapperBakedModelFabric
import net.minecraft.client.render.model.BakedModel import net.minecraft.client.render.model.BakedModel
import net.minecraft.client.render.model.WrapperBakedModel
import moe.nea.firmament.util.ErrorUtil
interface BakedModelExtra { interface BakedModelExtra {
companion object {
@JvmStatic
fun cast(originalModel: BakedModel): BakedModelExtra? {
var p = originalModel
for (i in 0..256) {
p = when (p) {
is BakedModelExtra -> return p
is WrapperBakedModel -> p.wrapped
is WrapperBakedModelFabric -> WrapperBakedModelFabric.unwrap(p)
else -> break
}
}
ErrorUtil.softError("Could not find a baked model for $originalModel")
return null
}
}
var tintOverrides_firmament: TintOverrides? var tintOverrides_firmament: TintOverrides?
fun getHeadModel_firmament(): BakedModel? fun getHeadModel_firmament(): BakedModel?

View File

@@ -244,7 +244,7 @@ object CustomBlockTextures {
.flatMap { it.lookup.values } .flatMap { it.lookup.values }
.flatten() .flatten()
.mapTo(mutableSetOf()) { it.replacement.blockModelIdentifier } .mapTo(mutableSetOf()) { it.replacement.blockModelIdentifier }
.forEach { event.addNonItemModel(it) } .forEach { event.addNonItemModel(it, it.id) }
} }
private fun prepare(manager: ResourceManager): BakedReplacements { private fun prepare(manager: ResourceManager): BakedReplacements {
@@ -263,7 +263,7 @@ object CustomBlockTextures {
val island = SkyBlockIsland.forMode(mode) val island = SkyBlockIsland.forMode(mode)
val islandMpa = map.getOrPut(island, ::mutableMapOf) val islandMpa = map.getOrPut(island, ::mutableMapOf)
for ((blockId, replacement) in json.replacements) { 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)) .getOptional(RegistryKey.of(RegistryKeys.BLOCK, blockId))
.getOrNull() .getOrNull()
if (block == null) { if (block == null) {

View File

@@ -3,13 +3,13 @@
package moe.nea.firmament.features.texturepack package moe.nea.firmament.features.texturepack
import java.util.Optional import java.util.Optional
import java.util.concurrent.atomic.AtomicInteger
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import kotlinx.serialization.UseSerializers import kotlinx.serialization.UseSerializers
import kotlin.jvm.optionals.getOrNull
import net.minecraft.item.ArmorMaterial
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.equipment.EquipmentModel
import net.minecraft.resource.ResourceManager import net.minecraft.resource.ResourceManager
import net.minecraft.resource.SinglePreparationResourceReloader import net.minecraft.resource.SinglePreparationResourceReloader
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
@@ -17,27 +17,31 @@ import net.minecraft.util.profiler.Profiler
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.FinalizeResourceManagerEvent 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.features.texturepack.CustomGlobalTextures.logger
import moe.nea.firmament.util.IdentifierSerializer import moe.nea.firmament.util.IdentifierSerializer
import moe.nea.firmament.util.collections.WeakCache import moe.nea.firmament.util.collections.WeakCache
import moe.nea.firmament.util.skyBlockId import moe.nea.firmament.util.skyBlockId
object CustomGlobalArmorOverrides : SubscriptionOwner { object CustomGlobalArmorOverrides {
@Serializable @Serializable
data class ArmorOverride( data class ArmorOverride(
@SerialName("item_ids") @SerialName("item_ids")
val itemIds: List<String>, val itemIds: List<String>,
val layers: List<ArmorOverrideLayer>, val layers: List<ArmorOverrideLayer>? = null,
val model: Identifier? = null,
val overrides: List<ArmorOverrideOverride> = listOf(), val overrides: List<ArmorOverrideOverride> = listOf(),
) { ) {
@Transient @Transient
val bakedLayers = bakeLayers(layers) lateinit var modelIdentifier: Identifier
fun bake() {
modelIdentifier = bakeModel(model, layers)
overrides.forEach { it.bake() }
} }
fun bakeLayers(layers: List<ArmorOverrideLayer>): List<ArmorMaterial.Layer> { init {
return layers.map { ArmorMaterial.Layer(it.identifier, it.suffix, it.tint) } 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 @Serializable
@@ -50,33 +54,66 @@ object CustomGlobalArmorOverrides : SubscriptionOwner {
@Serializable @Serializable
data class ArmorOverrideOverride( data class ArmorOverrideOverride(
val predicate: FirmamentModelPredicate, val predicate: FirmamentModelPredicate,
val layers: List<ArmorOverrideLayer>, val layers: List<ArmorOverrideLayer>? = null,
val model: Identifier? = null,
) { ) {
@Transient init {
val bakedLayers = bakeLayers(layers) 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" }
} }
override val delegateFeature: FirmamentFeature @Transient
get() = CustomSkyBlockTextures lateinit var modelIdentifier: Identifier
fun bake() {
modelIdentifier = bakeModel(model, layers)
}
}
val overrideCache = WeakCache.memoize<ItemStack, Optional<List<ArmorMaterial.Layer>>>("ArmorOverrides") { stack ->
val overrideCache = WeakCache.memoize<ItemStack, Optional<Identifier>>("ArmorOverrides") { stack ->
val id = stack.skyBlockId ?: return@memoize Optional.empty() val id = stack.skyBlockId ?: return@memoize Optional.empty()
val override = overrides[id.neuItem] ?: return@memoize Optional.empty() val override = overrides[id.neuItem] ?: return@memoize Optional.empty()
for (suboverride in override.overrides) { for (suboverride in override.overrides) {
if (suboverride.predicate.test(stack)) { if (suboverride.predicate.test(stack)) {
return@memoize Optional.of(suboverride.bakedLayers) return@memoize Optional.of(suboverride.modelIdentifier)
} }
} }
return@memoize Optional.of(override.bakedLayers) return@memoize Optional.of(override.modelIdentifier)
}
@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() 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 @Subscribe
fun onStart(event: FinalizeResourceManagerEvent) { fun onStart(event: FinalizeResourceManagerEvent) {
@@ -98,9 +135,21 @@ object CustomGlobalArmorOverrides : SubscriptionOwner {
} }
override fun apply(prepared: Map<String, ArmorOverride>, manager: ResourceManager, profiler: Profiler) { override fun apply(prepared: Map<String, ArmorOverride>, manager: ResourceManager, profiler: Profiler) {
bakedOverrides.clear()
prepared.forEach { it.value.bake() }
overrides = prepared overrides = prepared
} }
}) })
} }
@JvmStatic
fun overrideArmor(itemStack: ItemStack): Optional<Identifier> {
return overrideCache.invoke(itemStack)
}
@JvmStatic
fun overrideArmorLayer(id: Identifier): EquipmentModel? {
return bakedOverrides[id]
}
} }

View File

@@ -146,7 +146,7 @@ object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalText
it.overrides it.overrides
.asSequence() .asSequence()
.filter { it.predicate.test(stack) } .filter { it.predicate.test(stack) }
.map { models.modelManager.getModel(ModelIdentifier(it.model, "inventory")) } .map { models.getModel(it.model) }
.firstOrNull() .firstOrNull()
} }
.intoOptional() .intoOptional()

View File

@@ -1,9 +1,11 @@
package moe.nea.firmament.features.texturepack package moe.nea.firmament.features.texturepack
import net.minecraft.client.render.model.Baker
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
interface JsonUnbakedModelFirmExtra { interface JsonUnbakedModelFirmExtra {
fun storeExtraBaker_firmament(baker: Baker)
fun setHeadModel_firmament(identifier: Identifier?) fun setHeadModel_firmament(identifier: Identifier?)
fun getHeadModel_firmament(): Identifier? fun getHeadModel_firmament(): Identifier?

View File

@@ -3,7 +3,6 @@ package moe.nea.firmament.features.texturepack
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive import com.google.gson.JsonPrimitive
import moe.nea.firmament.util.ErrorUtil import moe.nea.firmament.util.ErrorUtil
import moe.nea.firmament.util.assertNotNullOr
data class TintOverrides( data class TintOverrides(
val layerMap: Map<Int, TintOverride> = mapOf() val layerMap: Map<Int, TintOverride> = mapOf()
@@ -14,21 +13,22 @@ data class TintOverrides(
val EMPTY = TintOverrides() val EMPTY = TintOverrides()
private val threadLocal = object : ThreadLocal<TintOverrides>() {} private val threadLocal = object : ThreadLocal<TintOverrides>() {}
fun enter(overrides: TintOverrides?) { fun enter(overrides: TintOverrides?) {
ErrorUtil.softCheck("Double entered tintOverrides") { ErrorUtil.softCheck("Double entered tintOverrides",
threadLocal.get() == null threadLocal.get() == null)
}
threadLocal.set(overrides ?: EMPTY) threadLocal.set(overrides ?: EMPTY)
} }
fun exit(overrides: TintOverrides?) { fun exit(overrides: TintOverrides?) {
ErrorUtil.softCheck("Exited with non matching enter tintOverrides") { ErrorUtil.softCheck("Exited with non matching enter tintOverrides",
threadLocal.get() == (overrides ?: EMPTY) threadLocal.get() == (overrides ?: EMPTY))
}
threadLocal.remove() threadLocal.remove()
} }
fun getCurrentOverrides() = fun getCurrentOverrides(): TintOverrides {
assertNotNullOr(threadLocal.get(), "Got current tintOverrides without entering") { EMPTY } return ErrorUtil.notNullOr(threadLocal.get(), "Got current tintOverrides without entering") {
EMPTY
}
}
fun parse(jsonObject: JsonObject): TintOverrides { fun parse(jsonObject: JsonObject): TintOverrides {
val map = mutableMapOf<Int, TintOverride>() val map = mutableMapOf<Int, TintOverride>()

View File

@@ -6,6 +6,7 @@ import io.github.moulberry.repo.data.Coordinate
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.serializer import kotlinx.serialization.serializer
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d import net.minecraft.util.math.Vec3d
import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.events.ProcessChatEvent
@@ -98,9 +99,8 @@ object FairySouls : FirmamentFeature {
fun onWorldRender(it: WorldRenderLastEvent) { fun onWorldRender(it: WorldRenderLastEvent) {
if (!TConfig.displaySouls) return if (!TConfig.displaySouls) return
renderInWorld(it) { renderInWorld(it) {
color(1F, 1F, 0F, 0.8F)
currentMissingSouls.forEach { currentMissingSouls.forEach {
block(it.blockPos) block(it.blockPos, 0x80FFFF00.toInt())
} }
color(1f, 0f, 1f, 1f) color(1f, 0f, 1f, 1f)
currentLocationSouls.forEach { currentLocationSouls.forEach {

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.features.world package moe.nea.firmament.features.world
import com.mojang.brigadier.arguments.IntegerArgumentType 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.hours
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import net.minecraft.command.argument.BlockPosArgumentType import net.minecraft.command.argument.BlockPosArgumentType
import net.minecraft.server.command.CommandOutput
import net.minecraft.server.command.ServerCommandSource import net.minecraft.server.command.ServerCommandSource
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
@@ -75,9 +74,7 @@ object Waypoints : FirmamentFeature {
RenderInWorldContext.renderInWorld(event) { RenderInWorldContext.renderInWorld(event) {
if (!ordered) { if (!ordered) {
waypoints.withIndex().forEach { waypoints.withIndex().forEach {
color(0f, 0.3f, 0.7f, 0.5f) block(it.value, 0x800050A0.toInt())
block(it.value)
color(1f, 1f, 1f, 1f)
if (TConfig.showIndex) if (TConfig.showIndex)
withFacingThePlayer(it.value.toCenterPos()) { withFacingThePlayer(it.value.toCenterPos()) {
text(Text.literal(it.index.toString())) text(Text.literal(it.index.toString()))
@@ -100,9 +97,7 @@ object Waypoints : FirmamentFeature {
.reversed() .reversed()
.forEach { (waypoint, col) -> .forEach { (waypoint, col) ->
val (index, pos) = waypoint val (index, pos) = waypoint
color(col) block(pos, col.color)
block(pos)
color(1f, 1f, 1f, 1f)
if (TConfig.showIndex) if (TConfig.showIndex)
withFacingThePlayer(pos.toCenterPos()) { withFacingThePlayer(pos.toCenterPos()) {
text(Text.literal(index.toString())) text(Text.literal(index.toString()))
@@ -231,11 +226,9 @@ object Waypoints : FirmamentFeature {
temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration } temporaryPlayerWaypointList.entries.removeIf { it.value.postedAt.passedTime() > TConfig.tempWaypointDuration }
if (temporaryPlayerWaypointList.isEmpty()) return if (temporaryPlayerWaypointList.isEmpty()) return
RenderInWorldContext.renderInWorld(event) { RenderInWorldContext.renderInWorld(event) {
color(1f, 1f, 0f, 1f)
temporaryPlayerWaypointList.forEach { (player, waypoint) -> temporaryPlayerWaypointList.forEach { (player, waypoint) ->
block(waypoint.pos) block(waypoint.pos, 0xFFFFFF00.toInt())
} }
color(1f, 1f, 1f, 1f)
temporaryPlayerWaypointList.forEach { (player, waypoint) -> temporaryPlayerWaypointList.forEach { (player, waypoint) ->
val skin = val skin =
MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player } MC.networkHandler?.listedPlayerListEntries?.find { it.profile.name == player }
@@ -284,7 +277,23 @@ fun <E> List<E>.wrappingWindow(startIndex: Int, windowSize: Int): List<E> {
fun FabricClientCommandSource.asFakeServer(): ServerCommandSource { fun FabricClientCommandSource.asFakeServer(): ServerCommandSource {
val source = this val source = this
return ServerCommandSource( return ServerCommandSource(
source.player, 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.position,
source.rotation, source.rotation,
null, null,

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.gui package moe.nea.firmament.gui
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
@@ -10,6 +9,7 @@ import io.github.notenoughupdates.moulconfig.observer.GetSetter
import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext import io.github.notenoughupdates.moulconfig.platform.ModernRenderContext
import me.shedaniel.math.Color import me.shedaniel.math.Color
import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.DrawContext
import net.minecraft.client.render.RenderLayer
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
@@ -33,13 +33,11 @@ class BarComponent(
) { ) {
fun draw(context: DrawContext, x: Int, y: Int, width: Int, height: Int, color: Color) { fun draw(context: DrawContext, x: Int, y: Int, width: Int, height: Int, color: Color) {
context.drawTexturedQuad( context.drawTexturedQuad(
RenderLayer::getGuiTextured,
identifier, identifier,
x, y, x + width, x + height, 0, x, y, x + width, x + height,
u1, u2, v1, v2, u1, u2, v1, v2,
color.red / 255F, color.color
color.green / 255F,
color.blue / 255F,
color.alpha / 255F,
) )
} }
} }

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.gui.entity package moe.nea.firmament.gui.entity
import com.google.gson.Gson import com.google.gson.Gson
@@ -13,7 +12,9 @@ import net.minecraft.client.gui.screen.ingame.InventoryScreen
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity import net.minecraft.entity.LivingEntity
import net.minecraft.entity.SpawnReason
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.world.World
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
import moe.nea.firmament.util.assertNotNullOr import moe.nea.firmament.util.assertNotNullOr
import moe.nea.firmament.util.iterate import moe.nea.firmament.util.iterate
@@ -21,9 +22,9 @@ import moe.nea.firmament.util.openFirmamentResource
import moe.nea.firmament.util.render.enableScissorWithTranslation import moe.nea.firmament.util.render.enableScissorWithTranslation
object EntityRenderer { object EntityRenderer {
val fakeWorld = FakeWorld() val fakeWorld: World get() = MC.lastWorld!!
private fun <T : Entity> t(entityType: EntityType<T>): () -> T { 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( val entityIds: Map<String, () -> LivingEntity> = mapOf(

View File

@@ -1,38 +1,37 @@
package moe.nea.firmament.gui.entity package moe.nea.firmament.gui.entity
import com.mojang.datafixers.util.Pair import java.util.UUID
import com.mojang.serialization.Lifecycle
import java.util.*
import java.util.function.BooleanSupplier import java.util.function.BooleanSupplier
import java.util.function.Consumer 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.Block
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.client.gui.screen.world.SelectWorldScreen
import net.minecraft.component.type.MapIdComponent import net.minecraft.component.type.MapIdComponent
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.entity.damage.DamageSource
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.fluid.Fluid import net.minecraft.fluid.Fluid
import net.minecraft.item.FuelRegistry
import net.minecraft.item.map.MapState import net.minecraft.item.map.MapState
import net.minecraft.particle.ParticleEffect
import net.minecraft.recipe.BrewingRecipeRegistry import net.minecraft.recipe.BrewingRecipeRegistry
import net.minecraft.recipe.Ingredient
import net.minecraft.recipe.RecipeManager 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.DynamicRegistryManager
import net.minecraft.registry.Registry import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKey import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys import net.minecraft.registry.RegistryKeys
import net.minecraft.registry.RegistryWrapper import net.minecraft.registry.ServerDynamicRegistryType
import net.minecraft.registry.entry.RegistryEntry import net.minecraft.registry.entry.RegistryEntry
import net.minecraft.registry.entry.RegistryEntryInfo import net.minecraft.resource.DataConfiguration
import net.minecraft.registry.entry.RegistryEntryList import net.minecraft.resource.ResourcePackManager
import net.minecraft.registry.entry.RegistryEntryOwner
import net.minecraft.registry.tag.TagKey
import net.minecraft.resource.featuretoggle.FeatureFlags import net.minecraft.resource.featuretoggle.FeatureFlags
import net.minecraft.resource.featuretoggle.FeatureSet import net.minecraft.resource.featuretoggle.FeatureSet
import net.minecraft.scoreboard.Scoreboard import net.minecraft.scoreboard.Scoreboard
import net.minecraft.server.SaveLoading
import net.minecraft.server.command.CommandManager
import net.minecraft.sound.SoundCategory import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvent import net.minecraft.sound.SoundEvent
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
@@ -43,11 +42,8 @@ import net.minecraft.util.math.Box
import net.minecraft.util.math.ChunkPos import net.minecraft.util.math.ChunkPos
import net.minecraft.util.math.Direction import net.minecraft.util.math.Direction
import net.minecraft.util.math.Vec3d 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.BlockView
import net.minecraft.world.Difficulty import net.minecraft.world.Difficulty
import net.minecraft.world.GameRules
import net.minecraft.world.MutableWorldProperties import net.minecraft.world.MutableWorldProperties
import net.minecraft.world.World import net.minecraft.world.World
import net.minecraft.world.biome.Biome import net.minecraft.world.biome.Biome
@@ -59,186 +55,15 @@ import net.minecraft.world.chunk.EmptyChunk
import net.minecraft.world.chunk.light.LightingProvider import net.minecraft.world.chunk.light.LightingProvider
import net.minecraft.world.entity.EntityLookup import net.minecraft.world.entity.EntityLookup
import net.minecraft.world.event.GameEvent import net.minecraft.world.event.GameEvent
import net.minecraft.world.explosion.ExplosionBehavior
import net.minecraft.world.tick.OrderedTick import net.minecraft.world.tick.OrderedTick
import net.minecraft.world.tick.QueryableTickScheduler import net.minecraft.world.tick.QueryableTickScheduler
import net.minecraft.world.tick.TickManager import net.minecraft.world.tick.TickManager
import moe.nea.firmament.util.MC
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 { fun createDynamicRegistry(): DynamicRegistryManager.Immutable {
val wrapperLookup = BuiltinRegistries.createWrapperLookup() // TODO: use SaveLoading.load() to properly load a full registry
return object : DynamicRegistryManager.Immutable { return DynamicRegistryManager.of(Registries.REGISTRIES)
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>>) }
}
}
} }
class FakeWorld( class FakeWorld(
@@ -247,16 +72,12 @@ class FakeWorld(
Properties, Properties,
RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")), RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")),
registries, registries,
registries[RegistryKeys.DIMENSION_TYPE].entryOf( MC.defaultRegistries.getOrThrow(RegistryKeys.DIMENSION_TYPE)
RegistryKey.of( .getOrThrow(RegistryKey.of(RegistryKeys.DIMENSION_TYPE, Identifier.of("minecraft", "overworld"))),
RegistryKeys.DIMENSION_TYPE,
Identifier.of("minecraft", "overworld")
)
),
{ DummyProfiler.INSTANCE },
true, true,
false, false,
0, 0 0L,
0
) { ) {
object Properties : MutableWorldProperties { object Properties : MutableWorldProperties {
override fun getSpawnPos(): BlockPos { override fun getSpawnPos(): BlockPos {
@@ -290,10 +111,6 @@ class FakeWorld(
return false return false
} }
override fun getGameRules(): GameRules {
return GameRules()
}
override fun getDifficulty(): Difficulty { override fun getDifficulty(): Difficulty {
return Difficulty.HARD return Difficulty.HARD
} }
@@ -314,7 +131,11 @@ class FakeWorld(
} }
override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> { override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> {
return registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS) return registryManager.getOptionalEntry(BiomeKeys.PLAINS).get()
}
override fun getSeaLevel(): Int {
return 0
} }
override fun getEnabledFeatures(): FeatureSet { override fun getEnabledFeatures(): FeatureSet {
@@ -353,7 +174,7 @@ class FakeWorld(
return EmptyChunk( return EmptyChunk(
world, world,
ChunkPos(x, z), ChunkPos(x, z),
world.registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS) world.registryManager.getOptionalEntry(BiomeKeys.PLAINS).get()
) )
} }
@@ -416,6 +237,23 @@ class FakeWorld(
) { ) {
} }
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 { override fun asString(): String {
return "FakeWorld" return "FakeWorld"
} }
@@ -447,7 +285,15 @@ class FakeWorld(
} }
override fun getRecipeManager(): RecipeManager { override fun getRecipeManager(): RecipeManager {
return RecipeManager(registryManager) 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> { object FakeEntityLookup : EntityLookup<Entity> {
@@ -485,4 +331,8 @@ class FakeWorld(
override fun getBrewingRecipeRegistry(): BrewingRecipeRegistry { override fun getBrewingRecipeRegistry(): BrewingRecipeRegistry {
return BrewingRecipeRegistry.EMPTY return BrewingRecipeRegistry.EMPTY
} }
override fun getFuelRegistry(): FuelRegistry {
TODO("Not yet implemented")
}
} }

View File

@@ -1,8 +1,7 @@
package moe.nea.firmament.gui.entity package moe.nea.firmament.gui.entity
import com.mojang.authlib.GameProfile import com.mojang.authlib.GameProfile
import java.util.* import java.util.UUID
import net.minecraft.client.network.AbstractClientPlayerEntity import net.minecraft.client.network.AbstractClientPlayerEntity
import net.minecraft.client.util.DefaultSkinHelper import net.minecraft.client.util.DefaultSkinHelper
import net.minecraft.client.util.SkinTextures import net.minecraft.client.util.SkinTextures
@@ -15,7 +14,7 @@ import net.minecraft.world.World
/** /**
* @see moe.nea.firmament.init.EarlyRiser * @see moe.nea.firmament.init.EarlyRiser
*/ */
fun makeGuiPlayer(world: FakeWorld): GuiPlayer { fun makeGuiPlayer(world: World): GuiPlayer {
val constructor = GuiPlayer::class.java.getDeclaredConstructor( val constructor = GuiPlayer::class.java.getDeclaredConstructor(
World::class.java, World::class.java,
BlockPos::class.java, BlockPos::class.java,

View File

@@ -8,6 +8,7 @@ import kotlin.experimental.inv
import kotlin.experimental.or import kotlin.experimental.or
import net.minecraft.entity.EntityType import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity import net.minecraft.entity.LivingEntity
import net.minecraft.entity.SpawnReason
import net.minecraft.entity.passive.AbstractHorseEntity import net.minecraft.entity.passive.AbstractHorseEntity
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.Items import net.minecraft.item.Items
@@ -19,11 +20,11 @@ object ModifyHorse : EntityModifier {
var entity: AbstractHorseEntity = entity var entity: AbstractHorseEntity = entity
info["kind"]?.let { info["kind"]?.let {
entity = when (it.asString) { entity = when (it.asString) {
"skeleton" -> EntityType.SKELETON_HORSE.create(fakeWorld)!! "skeleton" -> EntityType.SKELETON_HORSE.create(fakeWorld, SpawnReason.LOAD)!!
"zombie" -> EntityType.ZOMBIE_HORSE.create(fakeWorld)!! "zombie" -> EntityType.ZOMBIE_HORSE.create(fakeWorld, SpawnReason.LOAD)!!
"mule" -> EntityType.MULE.create(fakeWorld)!! "mule" -> EntityType.MULE.create(fakeWorld, SpawnReason.LOAD)!!
"donkey" -> EntityType.DONKEY.create(fakeWorld)!! "donkey" -> EntityType.DONKEY.create(fakeWorld, SpawnReason.LOAD)!!
"horse" -> EntityType.HORSE.create(fakeWorld)!! "horse" -> EntityType.HORSE.create(fakeWorld, SpawnReason.LOAD)!!
else -> error("Unknown horse kind $it") else -> error("Unknown horse kind $it")
} }
} }

View File

@@ -5,7 +5,7 @@ package moe.nea.firmament.repo
import io.ktor.client.call.body import io.ktor.client.call.body
import io.ktor.client.request.get import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsChannel 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.io.IOException
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path

View File

@@ -9,10 +9,12 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.minecraft.client.MinecraftClient import net.minecraft.client.MinecraftClient
import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket
import net.minecraft.recipe.display.CuttingRecipeDisplay
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.Firmament.logger import moe.nea.firmament.Firmament.logger
import moe.nea.firmament.events.ReloadRegistrationEvent import moe.nea.firmament.events.ReloadRegistrationEvent
import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.config.ManagedConfig
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.MinecraftDispatcher import moe.nea.firmament.util.MinecraftDispatcher
import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.SkyblockId
import moe.nea.firmament.util.tr import moe.nea.firmament.util.tr
@@ -77,7 +79,7 @@ object RepoManager {
private fun trySendClientboundUpdateRecipesPacket(): Boolean { private fun trySendClientboundUpdateRecipesPacket(): Boolean {
return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes( return MinecraftClient.getInstance().world != null && MinecraftClient.getInstance().networkHandler?.onSynchronizeRecipes(
SynchronizeRecipesS2CPacket(mutableListOf()) SynchronizeRecipesS2CPacket(mutableMapOf(), CuttingRecipeDisplay.Grouping.empty())
) != null ) != null
} }
@@ -92,7 +94,7 @@ object RepoManager {
fun launchAsyncUpdate(force: Boolean = false) { fun launchAsyncUpdate(force: Boolean = false) {
Firmament.coroutineScope.launch { Firmament.coroutineScope.launch {
ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper boundy bar ItemCache.ReloadProgressHud.reportProgress("Downloading", 0, -1) // TODO: replace with a proper bouncy bar
ItemCache.ReloadProgressHud.isEnabled = true ItemCache.ReloadProgressHud.isEnabled = true
try { try {
RepoDownloadManager.downloadUpdate(force) RepoDownloadManager.downloadUpdate(force)
@@ -112,7 +114,7 @@ object RepoManager {
ItemCache.ReloadProgressHud.isEnabled = true ItemCache.ReloadProgressHud.isEnabled = true
neuRepo.reload() neuRepo.reload()
} catch (exc: NEURepositoryException) { } catch (exc: NEURepositoryException) {
MinecraftClient.getInstance().player?.sendMessage( MC.sendChat(
tr("firmament.repo.reloadfail", tr("firmament.repo.reloadfail",
"Failed to reload repository. This will result in some mod features not working.") "Failed to reload repository. This will result in some mod features not working.")
) )

View File

@@ -1,9 +1,14 @@
package moe.nea.firmament.repo package moe.nea.firmament.repo
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import io.github.moulberry.repo.constants.PetNumbers import io.github.moulberry.repo.constants.PetNumbers
import io.github.moulberry.repo.data.NEUIngredient import io.github.moulberry.repo.data.NEUIngredient
import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.NEUItem
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.network.RegistryByteBuf
import net.minecraft.network.codec.PacketCodec
import net.minecraft.network.codec.PacketCodecs
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.Formatting import net.minecraft.util.Formatting
import moe.nea.firmament.repo.ItemCache.asItemStack import moe.nea.firmament.repo.ItemCache.asItemStack
@@ -40,6 +45,21 @@ data class SBItemStack constructor(
} }
companion object { companion object {
val PACKET_CODEC: PacketCodec<in RegistryByteBuf, SBItemStack> = PacketCodec.tuple(
SkyblockId.PACKET_CODEC, { it.skyblockId },
PacketCodecs.VAR_INT, { it.stackSize },
{ id, count -> SBItemStack(id, count) }
)
val CODEC: Codec<SBItemStack> = RecordCodecBuilder.create {
it.group(
SkyblockId.CODEC.fieldOf("skyblockId").forGetter { it.skyblockId },
Codec.INT.fieldOf("count").forGetter { it.stackSize },
).apply(it) { id, count ->
SBItemStack(id, count)
}
}
val EMPTY = SBItemStack(SkyblockId.NULL, 0)
operator fun invoke(itemStack: ItemStack): SBItemStack { operator fun invoke(itemStack: ItemStack): SBItemStack {
val skyblockId = itemStack.skyBlockId ?: SkyblockId.NULL val skyblockId = itemStack.skyBlockId ?: SkyblockId.NULL
return SBItemStack( return SBItemStack(
@@ -114,6 +134,8 @@ data class SBItemStack constructor(
val itemStack = itemStack_ ?: run { val itemStack = itemStack_ ?: run {
if (skyblockId == SkyblockId.COINS) if (skyblockId == SkyblockId.COINS)
return@run ItemCache.coinItem(stackSize).also { it.appendLore(extraLore) } return@run ItemCache.coinItem(stackSize).also { it.appendLore(extraLore) }
if (stackSize == 0)
return@run ItemStack.EMPTY
val replacementData = mutableMapOf<String, String>() val replacementData = mutableMapOf<String, String>()
injectReplacementDataForPets(replacementData) injectReplacementDataForPets(replacementData)
return@run neuItem.asItemStack(idHint = skyblockId, replacementData) return@run neuItem.asItemStack(idHint = skyblockId, replacementData)

View File

@@ -0,0 +1,19 @@
package moe.nea.firmament.repo.recipes
import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.data.NEURecipe
import me.shedaniel.math.Rectangle
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import moe.nea.firmament.repo.SBItemStack
interface GenericRecipeRenderer<T : NEURecipe> {
fun render(recipe: T, bounds: Rectangle, layouter: RecipeLayouter)
fun getInputs(recipe: T): Collection<SBItemStack>
fun getOutputs(recipe: T): Collection<SBItemStack>
val icon: ItemStack
val title: Text
val identifier: Identifier
fun findAllRecipes(neuRepository: NEURepository): Iterable<T>
}

View File

@@ -0,0 +1,33 @@
package moe.nea.firmament.repo.recipes
import io.github.notenoughupdates.moulconfig.gui.GuiComponent
import net.minecraft.text.Text
import moe.nea.firmament.repo.SBItemStack
interface RecipeLayouter {
enum class SlotKind {
SMALL_INPUT,
SMALL_OUTPUT,
/**
* Create a bigger background and mark the slot as output. The coordinates should still refer the upper left corner of the item stack, not of the bigger background.
*/
BIG_OUTPUT,
}
fun createItemSlot(
x: Int, y: Int,
content: SBItemStack?,
slotKind: SlotKind,
)
fun createLabel(
x: Int, y: Int,
text: Text
)
fun createArrow(x: Int, y: Int)
fun createMoulConfig(x: Int, y: Int, w: Int, h: Int, component: GuiComponent)
}

View File

@@ -0,0 +1,50 @@
package moe.nea.firmament.repo.recipes
import io.github.moulberry.repo.NEURepository
import io.github.moulberry.repo.data.NEUCraftingRecipe
import me.shedaniel.math.Point
import me.shedaniel.math.Rectangle
import net.minecraft.block.Blocks
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import moe.nea.firmament.Firmament
import moe.nea.firmament.repo.SBItemStack
import moe.nea.firmament.util.tr
class SBCraftingRecipeRenderer : GenericRecipeRenderer<NEUCraftingRecipe> {
override fun render(recipe: NEUCraftingRecipe, bounds: Rectangle, layouter: RecipeLayouter) {
val point = Point(bounds.centerX - 58, bounds.centerY - 27)
layouter.createArrow(point.x + 60, point.y + 18)
for (i in 0 until 3) {
for (j in 0 until 3) {
val item = recipe.inputs[i + j * 3]
layouter.createItemSlot(point.x + 1 + i * 18,
point.y + 1 + j * 18,
SBItemStack(item),
RecipeLayouter.SlotKind.SMALL_INPUT)
}
}
layouter.createItemSlot(
point.x + 95, point.y + 19,
SBItemStack(recipe.output),
RecipeLayouter.SlotKind.BIG_OUTPUT
)
}
override fun getInputs(recipe: NEUCraftingRecipe): Collection<SBItemStack> {
return recipe.allInputs.mapNotNull { SBItemStack(it) }
}
override fun getOutputs(recipe: NEUCraftingRecipe): Collection<SBItemStack> {
return SBItemStack(recipe.output)?.let(::listOf) ?: emptyList()
}
override fun findAllRecipes(neuRepository: NEURepository): Iterable<NEUCraftingRecipe> {
return neuRepository.items.items.values.flatMap { it.recipes }.filterIsInstance<NEUCraftingRecipe>()
}
override val icon: ItemStack = ItemStack(Blocks.CRAFTING_TABLE)
override val title: Text = tr("firmament.category.crafting", "SkyBlock Crafting")
override val identifier: Identifier = Firmament.identifier("crafting_recipe")
}

View File

@@ -1,25 +1,46 @@
@file:OptIn(ExperimentalContracts::class)
package moe.nea.firmament.util package moe.nea.firmament.util
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
@Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame
object ErrorUtil { object ErrorUtil {
var aggressiveErrors = run { var aggressiveErrors = run {
Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") } || Firmament.DEBUG Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") } || Firmament.DEBUG
|| ErrorUtil::class.java.desiredAssertionStatus()
} }
inline fun softCheck(message: String, func: () -> Boolean) { inline fun softCheck(message: String, check: Boolean) {
if (!check) softError(message)
}
inline fun lazyCheck(message: String, func: () -> Boolean) {
contract {
callsInPlace(func, InvocationKind.AT_MOST_ONCE)
}
if (!aggressiveErrors) return if (!aggressiveErrors) return
if (func()) return if (func()) return
error(message) error(message)
} }
@Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame inline fun softError(message: String, exception: Throwable) {
if (aggressiveErrors) throw IllegalStateException(message, exception)
else Firmament.logger.error(message, exception)
}
inline fun softError(message: String) { inline fun softError(message: String) {
if (aggressiveErrors) error(message) if (aggressiveErrors) error(message)
else Firmament.logger.error(message) else Firmament.logger.error(message)
} }
inline fun <T : Any> notNullOr(nullable: T?, message: String, orElse: () -> T): T { inline fun <T : Any> notNullOr(nullable: T?, message: String, orElse: () -> T): T {
contract {
callsInPlace(orElse, InvocationKind.AT_MOST_ONCE)
}
if (nullable == null) { if (nullable == null) {
softError(message) softError(message)
return orElse() return orElse()

View File

@@ -3,9 +3,13 @@ package moe.nea.firmament.util
import io.github.moulberry.repo.data.Coordinate import io.github.moulberry.repo.data.Coordinate
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.client.MinecraftClient import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.option.GameOptions import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.render.WorldRenderer import net.minecraft.client.render.WorldRenderer
import net.minecraft.client.render.item.ItemRenderer
import net.minecraft.client.world.ClientWorld
import net.minecraft.entity.Entity
import net.minecraft.item.Item import net.minecraft.item.Item
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
import net.minecraft.registry.BuiltinRegistries import net.minecraft.registry.BuiltinRegistries
@@ -14,7 +18,9 @@ import net.minecraft.registry.RegistryWrapper
import net.minecraft.resource.ReloadableResourceManagerImpl import net.minecraft.resource.ReloadableResourceManagerImpl
import net.minecraft.text.Text import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import moe.nea.firmament.events.TickEvent import moe.nea.firmament.events.TickEvent
import moe.nea.firmament.events.WorldReadyEvent
object MC { object MC {
@@ -29,6 +35,9 @@ object MC {
(nextTickTodos.poll() ?: break).invoke() (nextTickTodos.poll() ?: break).invoke()
} }
} }
WorldReadyEvent.subscribe("MC:ready") {
this.lastWorld
}
} }
fun sendChat(text: Text) { fun sendChat(text: Text) {
@@ -69,6 +78,7 @@ object MC {
inline val resourceManager get() = (instance.resourceManager as ReloadableResourceManagerImpl) inline val resourceManager get() = (instance.resourceManager as ReloadableResourceManagerImpl)
inline val itemRenderer: ItemRenderer get() = instance.itemRenderer
inline val worldRenderer: WorldRenderer get() = instance.worldRenderer inline val worldRenderer: WorldRenderer get() = instance.worldRenderer
inline val networkHandler get() = player?.networkHandler inline val networkHandler get() = player?.networkHandler
inline val instance get() = MinecraftClient.getInstance() inline val instance get() = MinecraftClient.getInstance()
@@ -79,11 +89,11 @@ object MC {
inline val inGameHud get() = instance.inGameHud inline val inGameHud get() = instance.inGameHud
inline val font get() = instance.textRenderer inline val font get() = instance.textRenderer
inline val soundManager get() = instance.soundManager inline val soundManager get() = instance.soundManager
inline val player get() = instance.player inline val player: ClientPlayerEntity? get() = instance.player
inline val camera get() = instance.cameraEntity inline val camera: Entity? get() = instance.cameraEntity
inline val guiAtlasManager get() = instance.guiAtlasManager inline val guiAtlasManager get() = instance.guiAtlasManager
inline val world get() = instance.world inline val world: ClientWorld? get() = instance.world
inline var screen inline var screen: Screen?
get() = instance.currentScreen get() = instance.currentScreen
set(value) = instance.setScreen(value) set(value) = instance.setScreen(value)
val screenName get() = screen?.title?.unformattedString?.trim() val screenName get() = screen?.title?.unformattedString?.trim()
@@ -92,7 +102,13 @@ object MC {
inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager inline val currentRegistries: RegistryWrapper.WrapperLookup? get() = world?.registryManager
val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup() val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup()
inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries
val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getWrapperOrThrow(RegistryKeys.ITEM) val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getOrThrow(RegistryKeys.ITEM)
var lastWorld: World? = null
get() {
field = world ?: field
return field
}
private set
} }

View File

@@ -37,7 +37,7 @@ object SBData {
it.serverType.getOrNull()?.name?.uppercase(), it.serverType.getOrNull()?.name?.uppercase(),
it.mode.getOrNull(), it.mode.getOrNull(),
it.map.getOrNull()) it.map.getOrNull())
SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, null)) SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, locraw))
profileIdCommandDebounce = TimeMark.now() profileIdCommandDebounce = TimeMark.now()
} }
} }

View File

@@ -2,6 +2,7 @@
package moe.nea.firmament.util package moe.nea.firmament.util
import com.mojang.serialization.Codec
import io.github.moulberry.repo.data.NEUIngredient import io.github.moulberry.repo.data.NEUIngredient
import io.github.moulberry.repo.data.NEUItem import io.github.moulberry.repo.data.NEUItem
import io.github.moulberry.repo.data.Rarity import io.github.moulberry.repo.data.Rarity
@@ -16,6 +17,9 @@ import net.minecraft.component.type.NbtComponent
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.Items import net.minecraft.item.Items
import net.minecraft.nbt.NbtCompound import net.minecraft.nbt.NbtCompound
import net.minecraft.network.RegistryByteBuf
import net.minecraft.network.codec.PacketCodec
import net.minecraft.network.codec.PacketCodecs
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import moe.nea.firmament.repo.ItemCache.asItemStack import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.repo.set import moe.nea.firmament.repo.set
@@ -68,6 +72,9 @@ value class SkyblockId(val neuItem: String) {
val NULL: SkyblockId = SkyblockId("null") val NULL: SkyblockId = SkyblockId("null")
val PET_NULL: SkyblockId = SkyblockId("null_pet") val PET_NULL: SkyblockId = SkyblockId("null_pet")
private val illlegalPathRegex = "[^a-z0-9_.-/]".toRegex() private val illlegalPathRegex = "[^a-z0-9_.-/]".toRegex()
val CODEC = Codec.STRING.xmap({ SkyblockId(it) }, { it.neuItem })
val PACKET_CODEC: PacketCodec<in RegistryByteBuf, SkyblockId> =
PacketCodecs.STRING.xmap({ SkyblockId(it) }, { it.neuItem })
} }
} }

View File

@@ -1,15 +1,12 @@
package moe.nea.firmament.util.data package moe.nea.firmament.util.data
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
import kotlin.reflect.KClass import kotlin.reflect.KClass
import net.minecraft.client.MinecraftClient
import net.minecraft.server.command.CommandOutput
import net.minecraft.text.Text import net.minecraft.text.Text
import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament
import moe.nea.firmament.events.ScreenChangeEvent import moe.nea.firmament.events.ScreenChangeEvent
import moe.nea.firmament.util.MC
interface IDataHolder<T> { interface IDataHolder<T> {
companion object { companion object {
@@ -43,9 +40,9 @@ interface IDataHolder<T> {
} }
} }
private fun warnForResetConfigs(player: CommandOutput) { private fun warnForResetConfigs() {
if (badLoads.isNotEmpty()) { if (badLoads.isNotEmpty()) {
player.sendMessage( MC.sendChat(
Text.literal( Text.literal(
"The following configs have been reset: ${badLoads.joinToString(", ")}. " + "The following configs have been reset: ${badLoads.joinToString(", ")}. " +
"This can be intentional, but probably isn't." "This can be intentional, but probably isn't."
@@ -58,10 +55,7 @@ interface IDataHolder<T> {
fun registerEvents() { fun registerEvents() {
ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event -> ScreenChangeEvent.subscribe("IDataHolder:saveOnScreenChange") { event ->
performSaves() performSaves()
val p = MinecraftClient.getInstance().player warnForResetConfigs()
if (p != null) {
warnForResetConfigs(p)
}
} }
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping { ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
performSaves() performSaves()

View File

@@ -4,12 +4,70 @@ import com.mojang.blaze3d.systems.RenderSystem
import me.shedaniel.math.Color import me.shedaniel.math.Color
import org.joml.Matrix4f import org.joml.Matrix4f
import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.DrawContext
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.RenderLayer.MultiPhaseParameters
import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats
import net.minecraft.util.Identifier
import net.minecraft.util.TriState
import net.minecraft.util.Util
import moe.nea.firmament.util.MC import moe.nea.firmament.util.MC
fun DrawContext.isUntranslatedGuiDrawContext(): Boolean { fun DrawContext.isUntranslatedGuiDrawContext(): Boolean {
return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0 return (matrices.peek().positionMatrix.properties() and Matrix4f.PROPERTY_IDENTITY.toInt()) != 0
} }
object GuiRenderLayers {
val GUI_TEXTURED_NO_DEPTH = Util.memoize<Identifier, RenderLayer> { texture: Identifier ->
RenderLayer.of("firmament_gui_textured_no_depth",
VertexFormats.POSITION_TEXTURE_COLOR,
VertexFormat.DrawMode.QUADS,
RenderLayer.CUTOUT_BUFFER_SIZE,
MultiPhaseParameters.builder()
.texture(RenderPhase.Texture(texture, TriState.FALSE, false))
.program(RenderPhase.POSITION_TEXTURE_COLOR_PROGRAM)
.transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
.depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
.build(false))
}
}
@Deprecated("Use the other drawGuiTexture")
fun DrawContext.drawGuiTexture(
x: Int, y: Int, z: Int, width: Int, height: Int, sprite: Identifier
) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height)
fun DrawContext.drawGuiTexture(
sprite: Identifier,
x: Int, y: Int, width: Int, height: Int
) = this.drawGuiTexture(RenderLayer::getGuiTextured, sprite, x, y, width, height)
fun DrawContext.drawTexture(
sprite: Identifier,
x: Int,
y: Int,
u: Float,
v: Float,
width: Int,
height: Int,
textureWidth: Int,
textureHeight: Int
) {
this.drawTexture(RenderLayer::getGuiTextured,
sprite,
x,
y,
u,
v,
width,
height,
width,
height,
textureWidth,
textureHeight)
}
fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Color) { fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Color) {
// TODO: push scissors // TODO: push scissors
// TODO: use matrix translations and a different render layer // TODO: use matrix translations and a different render layer
@@ -18,11 +76,12 @@ fun DrawContext.drawLine(fromX: Int, fromY: Int, toX: Int, toY: Int, color: Colo
return return
} }
RenderSystem.lineWidth(MC.window.scaleFactor.toFloat()) RenderSystem.lineWidth(MC.window.scaleFactor.toFloat())
val buf = this.vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES) draw { vertexConsumers ->
val buf = vertexConsumers.getBuffer(RenderInWorldContext.RenderLayers.LINES)
buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color) buf.vertex(fromX.toFloat(), fromY.toFloat(), 0F).color(color.color)
.normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color) buf.vertex(toX.toFloat(), toY.toFloat(), 0F).color(color.color)
.normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F) .normal(toX - fromX.toFloat(), toY - fromY.toFloat(), 0F)
this.draw() }
} }

View File

@@ -76,13 +76,10 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) {
u1: Float, v1: Float, u1: Float, v1: Float,
u2: Float, v2: Float, u2: Float, v2: Float,
) { ) {
RenderSystem.setShaderTexture(0, texture) val buf = worldContext.vertexConsumers.getBuffer(RenderLayer.getGuiTexturedOverlay(texture))
RenderSystem.setShader(GameRenderer::getPositionTexColorProgram)
val hw = width / 2F val hw = width / 2F
val hh = height / 2F val hh = height / 2F
val matrix4f: Matrix4f = worldContext.matrixStack.peek().positionMatrix 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) buf.vertex(matrix4f, -hw, -hh, 0F)
.color(-1) .color(-1)
.texture(u1, v1).next() .texture(u1, v1).next()
@@ -95,7 +92,7 @@ class FacingThePlayerContext(val worldContext: RenderInWorldContext) {
buf.vertex(matrix4f, +hw, -hh, 0F) buf.vertex(matrix4f, +hw, -hh, 0F)
.color(-1) .color(-1)
.texture(u2, v1).next() .texture(u2, v1).next()
BufferRenderer.drawWithGlobalProgram(buf.end()) worldContext.vertexConsumers.draw()
} }
} }

View File

@@ -1,23 +1,30 @@
package moe.nea.firmament.util.render 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.RenderPhase
import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats import net.minecraft.client.render.VertexFormats
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.RegisterCustomShadersEvent import moe.nea.firmament.events.DebugInstantiateEvent
import moe.nea.firmament.util.MC
object FirmamentShaders { object FirmamentShaders {
val shaders = mutableListOf<ShaderProgramKey>()
private fun shader(name: String, format: VertexFormat, defines: Defines): ShaderProgramKey {
val key = ShaderProgramKey(Firmament.identifier(name), format, defines)
shaders.add(key)
return key
}
private lateinit var _LINES: ShaderProgram val LINES = RenderPhase.ShaderProgram(shader("core/rendertype_lines", VertexFormats.LINES, Defines.EMPTY))
val LINES = RenderPhase.ShaderProgram({ _LINES })
@Subscribe @Subscribe
fun registerCustomShaders(event: RegisterCustomShadersEvent) { fun debugLoad(event: DebugInstantiateEvent) {
event.register( shaders.forEach {
"firmament_rendertype_lines", MC.instance.shaderLoader.getOrCreateProgram(it)
VertexFormats.LINES, }
{ _LINES = it },
)
} }
} }

View File

@@ -1,4 +1,3 @@
package moe.nea.firmament.util.render package moe.nea.firmament.util.render
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
@@ -9,7 +8,8 @@ import kotlin.math.atan2
import kotlin.math.tan import kotlin.math.tan
import net.minecraft.client.gui.DrawContext import net.minecraft.client.gui.DrawContext
import net.minecraft.client.render.BufferRenderer 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.Tessellator
import net.minecraft.client.render.VertexFormat.DrawMode import net.minecraft.client.render.VertexFormat.DrawMode
import net.minecraft.client.render.VertexFormats import net.minecraft.client.render.VertexFormats
@@ -26,11 +26,10 @@ object RenderCircleProgress {
v1: Float, v1: Float,
v2: Float, v2: Float,
) { ) {
RenderSystem.setShaderTexture(0, texture)
RenderSystem.setShader(GameRenderer::getPositionTexColorProgram)
RenderSystem.enableBlend() RenderSystem.enableBlend()
drawContext.draw {
val bufferBuilder = it.getBuffer(RenderLayer.getGuiTexturedOverlay(texture))
val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix val matrix: Matrix4f = drawContext.matrices.peek().positionMatrix
val bufferBuilder = Tessellator.getInstance().begin(DrawMode.TRIANGLES, VertexFormats.POSITION_TEXTURE_COLOR)
val corners = listOf( val corners = listOf(
Vector2f(0F, -1F), Vector2f(0F, -1F),
@@ -86,10 +85,9 @@ object RenderCircleProgress {
.color(-1) .color(-1)
.next() .next()
} }
BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()) }
RenderSystem.disableBlend() RenderSystem.disableBlend()
} }
} }

View File

@@ -1,5 +1,3 @@
package moe.nea.firmament.util.render package moe.nea.firmament.util.render
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
@@ -8,14 +6,12 @@ import java.lang.Math.pow
import org.joml.Matrix4f import org.joml.Matrix4f
import org.joml.Vector3f import org.joml.Vector3f
import net.minecraft.client.gl.VertexBuffer 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.Camera
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.RenderLayer import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.RenderPhase import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.RenderTickCounter import net.minecraft.client.render.RenderTickCounter
import net.minecraft.client.render.Tessellator import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexConsumerProvider import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.VertexFormat import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats import net.minecraft.client.render.VertexFormats
@@ -42,37 +38,51 @@ class RenderInWorldContext private constructor(
val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris", val TRANSLUCENT_TRIS = RenderLayer.of("firmament_translucent_tris",
VertexFormats.POSITION_COLOR, VertexFormats.POSITION_COLOR,
VertexFormat.DrawMode.TRIANGLES, VertexFormat.DrawMode.TRIANGLES,
RenderLayer.DEFAULT_BUFFER_SIZE, RenderLayer.CUTOUT_BUFFER_SIZE,
false, true, false, true,
RenderLayer.MultiPhaseParameters.builder() RenderLayer.MultiPhaseParameters.builder()
.depthTest(RenderPhase.ALWAYS_DEPTH_TEST) .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
.transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY) .transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
.program(RenderPhase.COLOR_PROGRAM) .program(RenderPhase.POSITION_COLOR_PROGRAM)
.build(false)) .build(false))
val LINES = RenderLayer.of("firmament_rendertype_lines", val LINES = RenderLayer.of("firmament_rendertype_lines",
VertexFormats.LINES, VertexFormats.LINES,
VertexFormat.DrawMode.LINES, VertexFormat.DrawMode.LINES,
RenderLayer.DEFAULT_BUFFER_SIZE, RenderLayer.CUTOUT_BUFFER_SIZE,
false, false, // do we need translucent? i dont think so false, false, // do we need translucent? i dont think so
RenderLayer.MultiPhaseParameters.builder() RenderLayer.MultiPhaseParameters.builder()
.depthTest(RenderPhase.ALWAYS_DEPTH_TEST) .depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
.program(FirmamentShaders.LINES) .program(FirmamentShaders.LINES)
.build(false) .build(false)
) )
val COLORED_QUADS = RenderLayer.of(
"firmament_quads",
VertexFormats.POSITION_COLOR,
VertexFormat.DrawMode.QUADS,
RenderLayer.CUTOUT_BUFFER_SIZE,
false, true,
RenderLayer.MultiPhaseParameters.builder()
.depthTest(RenderPhase.ALWAYS_DEPTH_TEST)
.program(RenderPhase.POSITION_COLOR_PROGRAM)
.transparency(RenderPhase.TRANSLUCENT_TRANSPARENCY)
.build(false)
)
} }
@Deprecated("stateful color management is no longer a thing")
fun color(color: me.shedaniel.math.Color) { fun color(color: me.shedaniel.math.Color) {
color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f) color(color.red / 255F, color.green / 255f, color.blue / 255f, color.alpha / 255f)
} }
@Deprecated("stateful color management is no longer a thing")
fun color(red: Float, green: Float, blue: Float, alpha: Float) { fun color(red: Float, green: Float, blue: Float, alpha: Float) {
RenderSystem.setShaderColor(red, green, blue, alpha) RenderSystem.setShaderColor(red, green, blue, alpha)
} }
fun block(blockPos: BlockPos) { fun block(blockPos: BlockPos, color: Int) {
matrixStack.push() matrixStack.push()
matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat())
buildCube(matrixStack.peek().positionMatrix, tesselator) buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayers.COLORED_QUADS), color)
matrixStack.pop() matrixStack.pop()
} }
@@ -129,29 +139,36 @@ class RenderInWorldContext private constructor(
} }
} }
fun text(position: Vec3d, vararg texts: Text, verticalAlign: VerticalAlign = VerticalAlign.CENTER, background: Int = 0x70808080) { fun text(
position: Vec3d,
vararg texts: Text,
verticalAlign: VerticalAlign = VerticalAlign.CENTER,
background: Int = 0x70808080
) {
withFacingThePlayer(position) { withFacingThePlayer(position) {
text(*texts, verticalAlign = verticalAlign, background = background) text(*texts, verticalAlign = verticalAlign, background = background)
} }
} }
fun tinyBlock(vec3d: Vec3d, size: Float) { fun tinyBlock(vec3d: Vec3d, size: Float, color: Int) {
RenderSystem.setShader(GameRenderer::getPositionColorProgram)
matrixStack.push() matrixStack.push()
matrixStack.translate(vec3d.x, vec3d.y, vec3d.z) matrixStack.translate(vec3d.x, vec3d.y, vec3d.z)
matrixStack.scale(size, size, size) matrixStack.scale(size, size, size)
matrixStack.translate(-.5, -.5, -.5) matrixStack.translate(-.5, -.5, -.5)
buildCube(matrixStack.peek().positionMatrix, tesselator) buildCube(matrixStack.peek().positionMatrix, vertexConsumers.getBuffer(RenderLayers.COLORED_QUADS), color)
matrixStack.pop() matrixStack.pop()
vertexConsumers.draw()
} }
fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) { fun wireframeCube(blockPos: BlockPos, lineWidth: Float = 10F) {
RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram) val buf = vertexConsumers.getBuffer(RenderLayer.LINES)
matrixStack.push() matrixStack.push()
// TODO: this does not render through blocks (or water layers) anymore
RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat()) RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(blockPos.toCenterPos()), 0.25).toFloat())
matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat()) matrixStack.translate(blockPos.x.toFloat(), blockPos.y.toFloat(), blockPos.z.toFloat())
buildWireFrameCube(matrixStack.peek(), tesselator) buildWireFrameCube(matrixStack.peek(), buf)
matrixStack.pop() matrixStack.pop()
vertexConsumers.draw()
} }
fun line(vararg points: Vec3d, lineWidth: Float = 10F) { fun line(vararg points: Vec3d, lineWidth: Float = 10F) {
@@ -165,6 +182,7 @@ class RenderInWorldContext private constructor(
fun line(points: List<Vec3d>, lineWidth: Float = 10F) { fun line(points: List<Vec3d>, lineWidth: Float = 10F) {
RenderSystem.lineWidth(lineWidth) RenderSystem.lineWidth(lineWidth)
// TODO: replace with renderlayers
val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES) val buffer = tesselator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
val matrix = matrixStack.peek() val matrix = matrixStack.peek()
@@ -187,11 +205,12 @@ class RenderInWorldContext private constructor(
RenderLayers.LINES.draw(buffer.end()) RenderLayers.LINES.draw(buffer.end())
} }
// TODO: put the favourite icons in front of items again
companion object { companion object {
private fun doLine( private fun doLine(
matrix: MatrixStack.Entry, matrix: MatrixStack.Entry,
buf: BufferBuilder, buf: VertexConsumer,
i: Float, i: Float,
j: Float, j: Float,
k: Float, k: Float,
@@ -213,9 +232,7 @@ class RenderInWorldContext private constructor(
} }
private fun buildWireFrameCube(matrix: MatrixStack.Entry, tessellator: Tessellator) { private fun buildWireFrameCube(matrix: MatrixStack.Entry, buf: VertexConsumer) {
val buf = tessellator.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
for (i in 0..1) { for (i in 0..1) {
for (j in 0..1) { for (j in 0..1) {
val i = i.toFloat() val i = i.toFloat()
@@ -225,52 +242,45 @@ class RenderInWorldContext private constructor(
doLine(matrix, buf, i, j, 0F, i, j, 1F) doLine(matrix, buf, i, j, 0F, i, j, 1F)
} }
} }
BufferRenderer.drawWithGlobalProgram(buf.end())
} }
private fun buildCube(matrix: Matrix4f, tessellator: Tessellator) { private fun buildCube(matrix: Matrix4f, buf: VertexConsumer, color: Int) {
val buf = tessellator.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR) // Y-
buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() buf.vertex(matrix, 0F, 0F, 0F).color(color)
buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() buf.vertex(matrix, 0F, 0F, 1F).color(color)
buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() buf.vertex(matrix, 1F, 0F, 1F).color(color)
buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() buf.vertex(matrix, 1F, 0F, 0F).color(color)
buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() // Y+
buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() buf.vertex(matrix, 0F, 1F, 0F).color(color)
buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() buf.vertex(matrix, 1F, 1F, 0F).color(color)
buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() buf.vertex(matrix, 1F, 1F, 1F).color(color)
buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() buf.vertex(matrix, 0F, 1F, 1F).color(color)
buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() // X-
buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() buf.vertex(matrix, 0F, 0F, 0F).color(color)
buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() buf.vertex(matrix, 0F, 0F, 1F).color(color)
buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() buf.vertex(matrix, 0F, 1F, 1F).color(color)
buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() buf.vertex(matrix, 0F, 1F, 0F).color(color)
buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next() // X+
buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() buf.vertex(matrix, 1F, 0F, 0F).color(color)
buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() buf.vertex(matrix, 1F, 1F, 0F).color(color)
buf.vertex(matrix, 0.0F, 0.0F, 0.0F).color(-1).next() buf.vertex(matrix, 1F, 1F, 1F).color(color)
buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next() buf.vertex(matrix, 1F, 0F, 1F).color(color)
buf.vertex(matrix, 0.0F, 0.0F, 1.0F).color(-1).next() // Z-
buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() buf.vertex(matrix, 0F, 0F, 0F).color(color)
buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() buf.vertex(matrix, 1F, 0F, 0F).color(color)
buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() buf.vertex(matrix, 1F, 1F, 0F).color(color)
buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() buf.vertex(matrix, 0F, 1F, 0F).color(color)
buf.vertex(matrix, 1.0F, 0.0F, 0.0F).color(-1).next() // Z+
buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() buf.vertex(matrix, 0F, 0F, 1F).color(color)
buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next() buf.vertex(matrix, 0F, 1F, 1F).color(color)
buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next() buf.vertex(matrix, 1F, 1F, 1F).color(color)
buf.vertex(matrix, 1.0F, 1.0F, 0.0F).color(-1).next() buf.vertex(matrix, 1F, 0F, 1F).color(color)
buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
buf.vertex(matrix, 0.0F, 1.0F, 0.0F).color(-1).next()
buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
buf.vertex(matrix, 1.0F, 1.0F, 1.0F).color(-1).next()
buf.vertex(matrix, 0.0F, 1.0F, 1.0F).color(-1).next()
buf.vertex(matrix, 1.0F, 0.0F, 1.0F).color(-1).next()
RenderLayers.TRANSLUCENT_TRIS.draw(buf.end())
} }
fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) { fun renderInWorld(event: WorldRenderLastEvent, block: RenderInWorldContext. () -> Unit) {
// TODO: there should be *no more global state*. the only thing we should be doing is render layers. that includes settings like culling, blending, shader color, and depth testing
// For now i will let these functions remain, but this needs to go before i do a full (non-beta) release
RenderSystem.disableDepthTest() RenderSystem.disableDepthTest()
RenderSystem.enableBlend() RenderSystem.enableBlend()
RenderSystem.defaultBlendFunc() RenderSystem.defaultBlendFunc()
@@ -290,7 +300,7 @@ class RenderInWorldContext private constructor(
block(ctx) block(ctx)
event.matrices.pop() event.matrices.pop()
event.vertexConsumers.draw()
RenderSystem.setShaderColor(1F, 1F, 1F, 1F) RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
VertexBuffer.unbind() VertexBuffer.unbind()
RenderSystem.enableDepthTest() RenderSystem.enableDepthTest()

Some files were not shown because too many files have changed in this diff Show More