aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt2
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt28
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt4
-rw-r--r--src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt2
-rw-r--r--src/main/kotlin/features/debug/PowerUserTools.kt4
-rw-r--r--src/main/kotlin/features/debug/itemeditor/ItemExporter.kt2
-rw-r--r--src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt9
-rw-r--r--src/main/kotlin/features/inventory/SlotLocking.kt68
-rw-r--r--src/main/kotlin/features/inventory/TimerInLore.kt1
-rw-r--r--src/main/kotlin/features/items/EtherwarpOverlay.kt3
-rw-r--r--src/main/kotlin/features/macros/RadialMenu.kt6
-rw-r--r--src/main/kotlin/repo/RepoManager.kt32
-rw-r--r--src/main/kotlin/util/render/LerpUtils.kt6
-rw-r--r--src/main/kotlin/util/skyblock/SkyBlockItems.kt1
-rw-r--r--src/main/resources/firmament.accesswidener5
-rw-r--r--src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt121
-rw-r--r--src/texturePacks/java/moe/nea/firmament/mixins/custommodels/LoadExtraBlockStates.java34
17 files changed, 279 insertions, 49 deletions
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt
index 98ac276..71e867a 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiCommonPlugin.kt
@@ -2,9 +2,11 @@ package moe.nea.firmament.compat.rei
import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry
import me.shedaniel.rei.api.common.plugins.REICommonPlugin
+import moe.nea.firmament.repo.RepoManager
class FirmamentReiCommonPlugin : REICommonPlugin {
override fun registerEntryTypes(registry: EntryTypeRegistry) {
+ if (!RepoManager.shouldLoadREI()) return
registry.register(FirmamentReiPlugin.SKYBLOCK_ITEM_TYPE_ID, SBItemEntryDefinition)
}
}
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt
index 89c3e19..3a494b9 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/FirmamentReiPlugin.kt
@@ -55,6 +55,7 @@ class FirmamentReiPlugin : REIClientPlugin {
@OptIn(ExpensiveItemCacheApi::class)
override fun registerTransferHandlers(registry: TransferHandlerRegistry) {
+ if (!RepoManager.shouldLoadREI()) return
registry.register(TransferHandler { context ->
val screen = context.containerScreen
val display = context.display
@@ -64,8 +65,11 @@ class FirmamentReiPlugin : REIClientPlugin {
val neuItem = RepoManager.getNEUItem(SkyblockId(recipe.output.itemId))
?: error("Could not find neu item ${recipe.output.itemId} which is used in a recipe output")
val useSuperCraft = context.isStackedCrafting || RepoManager.Config.alwaysSuperCraft
- if (neuItem.isVanilla && useSuperCraft) return@TransferHandler TransferHandler.Result.createFailed(Text.translatable(
- "firmament.recipe.novanilla"))
+ if (neuItem.isVanilla && useSuperCraft) return@TransferHandler TransferHandler.Result.createFailed(
+ Text.translatable(
+ "firmament.recipe.novanilla"
+ )
+ )
var shouldReturn = true
if (context.isActuallyCrafting && !useSuperCraft) {
val craftingScreen = (screen as? GenericContainerScreen)
@@ -85,13 +89,16 @@ class FirmamentReiPlugin : REIClientPlugin {
}
- val generics = listOf<GenericREIRecipeCategory<*>>( // Order matters: The order in here is the order in which they show up in REI
+ val generics = listOf<GenericREIRecipeCategory<*>>(
+ // Order matters: The order in here is the order in which they show up in REI
GenericREIRecipeCategory(SBCraftingRecipeRenderer),
GenericREIRecipeCategory(SBForgeRecipeRenderer),
GenericREIRecipeCategory(SBEssenceUpgradeRecipeRenderer),
)
override fun registerCategories(registry: CategoryRegistry) {
+ if (!RepoManager.shouldLoadREI()) return
+
registry.add(generics)
registry.add(SBMobDropRecipe.Category)
registry.add(SBKatRecipe.Category)
@@ -105,6 +112,8 @@ class FirmamentReiPlugin : REIClientPlugin {
}
override fun registerDisplays(registry: DisplayRegistry) {
+ if (!RepoManager.shouldLoadREI()) return
+
generics.forEach {
it.registerDynamicGenerator(registry)
}
@@ -114,16 +123,21 @@ class FirmamentReiPlugin : REIClientPlugin {
)
registry.registerDisplayGenerator(
SBMobDropRecipe.Category.categoryIdentifier,
- SkyblockMobDropRecipeDynamicGenerator)
+ SkyblockMobDropRecipeDynamicGenerator
+ )
registry.registerDisplayGenerator(
SBShopRecipe.Category.categoryIdentifier,
- SkyblockShopRecipeDynamicGenerator)
+ SkyblockShopRecipeDynamicGenerator
+ )
registry.registerDisplayGenerator(
SBKatRecipe.Category.categoryIdentifier,
- SkyblockKatRecipeDynamicGenerator)
+ SkyblockKatRecipeDynamicGenerator
+ )
}
override fun registerCollapsibleEntries(registry: CollapsibleEntryRegistry) {
+ if (!RepoManager.shouldLoadREI()) return
+
if (!RepoManager.Config.disableItemGroups)
RepoManager.neuRepo.constants.parents.parents
.forEach { (parent, children) ->
@@ -148,6 +162,8 @@ class FirmamentReiPlugin : REIClientPlugin {
}
override fun registerEntries(registry: EntryRegistry) {
+ if (!RepoManager.shouldLoadREI()) return
+
registry.removeEntryIf { true }
RepoManager.neuRepo.items?.items?.values?.forEach { neuItem ->
registry.addEntry(SBItemEntryDefinition.getEntry(neuItem.skyblockId))
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt
index d73500a..5e4eee3 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt
@@ -45,7 +45,7 @@ object NEUItemEntryRenderer : EntryRenderer<SBItemStack> {
delta: Float
) {
val neuItem = entry.value.neuItem
- val itemToRender = if(RepoManager.Config.perfectRenders < RepoManager.PerfectRender.RENDER && !entry.value.isWarm() && neuItem != null) {
+ val itemToRender = if(!RepoManager.Config.perfectRenders.rendersPerfectVisuals() && !entry.value.isWarm() && neuItem != null) {
ItemCache.recacheSoon(neuItem)
ItemStack(Items.PAINTING)
} else {
@@ -72,7 +72,7 @@ object NEUItemEntryRenderer : EntryRenderer<SBItemStack> {
@OptIn(ExpensiveItemCacheApi::class)
override fun getTooltip(entry: EntryStack<SBItemStack>, tooltipContext: TooltipContext): Tooltip? {
- if (!entry.value.isWarm() && RepoManager.Config.perfectRenders < RepoManager.PerfectRender.RENDER_AND_TEXT) {
+ if (!entry.value.isWarm() && !RepoManager.Config.perfectRenders.rendersPerfectText()) {
val neuItem = entry.value.neuItem
if (neuItem != null) {
val lore = mutableListOf<Text>()
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt
index 1d0a611..740eeeb 100644
--- a/src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt
+++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/SBItemEntryDefinition.kt
@@ -46,7 +46,7 @@ object SBItemEntryDefinition : EntryDefinition<SBItemStack> {
@OptIn(ExpensiveItemCacheApi::class)
override fun asFormattedText(entry: EntryStack<SBItemStack>, value: SBItemStack): Text {
val neuItem = entry.value.neuItem
- return if (RepoManager.Config.perfectRenders < RepoManager.PerfectRender.RENDER_AND_TEXT || entry.value.isWarm() || neuItem == null) {
+ return if (!RepoManager.Config.perfectRenders.rendersPerfectText() || entry.value.isWarm() || neuItem == null) {
VanillaEntryTypes.ITEM.definition.asFormattedText(entry.asItemEntry(), value.asImmutableItemStack())
} else {
Text.literal(neuItem.displayName)
diff --git a/src/main/kotlin/features/debug/PowerUserTools.kt b/src/main/kotlin/features/debug/PowerUserTools.kt
index 1a7b2cf..0800a4f 100644
--- a/src/main/kotlin/features/debug/PowerUserTools.kt
+++ b/src/main/kotlin/features/debug/PowerUserTools.kt
@@ -41,6 +41,7 @@ import moe.nea.firmament.util.mc.iterableArmorItems
import moe.nea.firmament.util.mc.loreAccordingToNbt
import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.tr
+import moe.nea.firmament.util.grey
object PowerUserTools : FirmamentFeature {
override val identifier: String
@@ -60,6 +61,7 @@ object PowerUserTools : FirmamentFeature {
val exportUIRecipes by keyBindingWithDefaultUnbound("export-recipe")
val exportNpcLocation by keyBindingWithDefaultUnbound("export-npc-location")
val highlightNonOverlayItems by toggle("highlight-non-overlay") { false }
+ val dontHighlightSemicolonItems by toggle("dont-highlight-semicolon-items") { false }
}
override val config
@@ -228,7 +230,7 @@ object PowerUserTools : FirmamentFeature {
fun addItemId(it: ItemTooltipEvent) {
if (TConfig.showItemIds) {
val id = it.stack.skyBlockId ?: return
- it.lines.add(Text.stringifiedTranslatable("firmament.tooltip.skyblockid", id.neuItem))
+ it.lines.add(Text.stringifiedTranslatable("firmament.tooltip.skyblockid", id.neuItem).grey())
}
val (item, text) = lastCopiedStack ?: return
if (!ItemStack.areEqual(item, it.stack)) {
diff --git a/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt b/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
index c521b5a..2a56204 100644
--- a/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
+++ b/src/main/kotlin/features/debug/itemeditor/ItemExporter.kt
@@ -215,6 +215,8 @@ object ItemExporter {
return
}
val stack = event.slot.stack ?: return
+ val id = event.slot.stack.skyBlockId?.neuItem
+ if (PowerUserTools.TConfig.dontHighlightSemicolonItems && id != null && id.contains(";")) return
val isExported = nonOverlayCache.getOrPut(stack.skyBlockId ?: return) {
RepoDownloadManager.repoSavedLocation.resolve("itemsOverlay")
.resolve(ExportedTestConstantMeta.current.dataVersion.toString())
diff --git a/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt b/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt
index ad03b16..ecf3d2c 100644
--- a/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt
+++ b/src/main/kotlin/features/debug/itemeditor/LegacyItemExporter.kt
@@ -5,6 +5,7 @@ import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlin.concurrent.thread
+import kotlin.jvm.optionals.getOrNull
import net.minecraft.component.DataComponentTypes
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtByte
@@ -14,6 +15,7 @@ import net.minecraft.nbt.NbtInt
import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtOps
import net.minecraft.nbt.NbtString
+import net.minecraft.registry.tag.ItemTags
import net.minecraft.text.Text
import net.minecraft.util.Unit
import moe.nea.firmament.Firmament
@@ -39,6 +41,7 @@ import moe.nea.firmament.util.unformattedString
class LegacyItemExporter private constructor(var itemStack: ItemStack) {
init {
require(!itemStack.isEmpty)
+ itemStack.count = 1
}
var lore = itemStack.loreAccordingToNbt
@@ -171,7 +174,11 @@ class LegacyItemExporter private constructor(var itemStack: ItemStack) {
}
private fun copyColour() {
- val leatherTint = itemStack.get(DataComponentTypes.DYED_COLOR) ?: return
+ if (!itemStack.isIn(ItemTags.DYEABLE)) {
+ itemStack.remove(DataComponentTypes.DYED_COLOR)
+ return
+ }
+ val leatherTint = itemStack.componentChanges.get(DataComponentTypes.DYED_COLOR)?.getOrNull() ?: return
legacyNbt.getOrPutCompound("display").put("color", NbtInt.of(leatherTint.rgb))
}
diff --git a/src/main/kotlin/features/inventory/SlotLocking.kt b/src/main/kotlin/features/inventory/SlotLocking.kt
index d3348a2..0a3f01b 100644
--- a/src/main/kotlin/features/inventory/SlotLocking.kt
+++ b/src/main/kotlin/features/inventory/SlotLocking.kt
@@ -4,7 +4,6 @@ package moe.nea.firmament.features.inventory
import java.util.UUID
import org.lwjgl.glfw.GLFW
-import util.render.CustomRenderLayers
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers
@@ -19,9 +18,8 @@ import kotlinx.serialization.json.int
import kotlinx.serialization.serializer
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.render.RenderLayer
-import net.minecraft.client.render.RenderLayers
-import net.minecraft.client.render.TexturedRenderLayers
import net.minecraft.entity.player.PlayerInventory
+import net.minecraft.item.ItemStack
import net.minecraft.screen.GenericContainerScreenHandler
import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType
@@ -44,14 +42,20 @@ import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData
import moe.nea.firmament.util.SkyBlockIsland
import moe.nea.firmament.util.data.ProfileSpecificDataHolder
+import moe.nea.firmament.util.extraAttributes
import moe.nea.firmament.util.json.DashlessUUIDSerializer
+import moe.nea.firmament.util.lime
import moe.nea.firmament.util.mc.ScreenUtil.getSlotByIndex
import moe.nea.firmament.util.mc.SlotUtils.swapWithHotBar
import moe.nea.firmament.util.mc.displayNameAccordingToNbt
import moe.nea.firmament.util.mc.loreAccordingToNbt
+import moe.nea.firmament.util.red
import moe.nea.firmament.util.render.drawLine
+import moe.nea.firmament.util.skyBlockId
import moe.nea.firmament.util.skyblock.DungeonUtil
+import moe.nea.firmament.util.skyblock.SkyBlockItems
import moe.nea.firmament.util.skyblockUUID
+import moe.nea.firmament.util.tr
import moe.nea.firmament.util.unformattedString
object SlotLocking : FirmamentFeature {
@@ -132,6 +136,7 @@ object SlotLocking : FirmamentFeature {
val slotBindRequireShift by toggle("require-quick-move") { true }
val slotRenderLines by choice("bind-render") { SlotRenderLinesMode.ONLY_BOXES }
val allowMultiBinding by toggle("multi-bind") { true } // TODO: filter based on this option
+ val protectAllHuntingBoxes by toggle("hunting-box") { false }
val allowDroppingInDungeons by toggle("drop-in-dungeons") { true }
}
@@ -193,10 +198,12 @@ object SlotLocking : FirmamentFeature {
var anyBlocked = false
for (i in 0 until event.slot.index) {
val stack = inv.getStack(i)
- if (IsSlotProtectedEvent.shouldBlockInteraction(null,
- SlotActionType.THROW,
- IsSlotProtectedEvent.MoveOrigin.SALVAGE,
- stack)
+ if (IsSlotProtectedEvent.shouldBlockInteraction(
+ null,
+ SlotActionType.THROW,
+ IsSlotProtectedEvent.MoveOrigin.SALVAGE,
+ stack
+ )
)
anyBlocked = true
}
@@ -219,12 +226,20 @@ object SlotLocking : FirmamentFeature {
&& doesNotDeleteItem
) return
val stack = event.itemStack ?: return
+ if (TConfig.protectAllHuntingBoxes && (stack.isHuntingBox())) {
+ event.protect()
+ return
+ }
val uuid = stack.skyblockUUID ?: return
if (uuid in (lockedUUIDs ?: return)) {
event.protect()
}
}
+ fun ItemStack.isHuntingBox(): Boolean {
+ return skyBlockId == SkyBlockItems.HUNTING_TOOLKIT || extraAttributes.get("tool_kit") != null
+ }
+
@Subscribe
fun onProtectSlot(it: IsSlotProtectedEvent) {
if (it.slot != null && it.slot.inventory is PlayerInventory && it.slot.index in (lockedSlots ?: setOf())) {
@@ -271,6 +286,21 @@ object SlotLocking : FirmamentFeature {
val slot = inventory.focusedSlot_Firmament ?: return
val stack = slot.stack ?: return
+ if (stack.isHuntingBox()) {
+ MC.sendChat(
+ tr(
+ "firmament.slot-locking.hunting-box-unbindable-hint",
+ "The hunting box cannot be UUID bound reliably. It changes its own UUID frequently when switching tools. "
+ ).red().append(
+ tr(
+ "firmament.slot-locking.hunting-box-unbindable-hint.solution",
+ "Use the Firmament config option for locking all hunting boxes instead."
+ ).lime()
+ )
+ )
+ CommonSoundEffects.playFailure()
+ return
+ }
val uuid = stack.skyblockUUID ?: return
val lockedUUIDs = lockedUUIDs ?: return
if (uuid in lockedUUIDs) {
@@ -350,12 +380,16 @@ object SlotLocking : FirmamentFeature {
hotX + sx, hotY + sy,
color(anyHovered)
)
- event.context.drawBorder(hotbarSlot.x + sx,
- hotbarSlot.y + sy,
- 16, 16, color(hotbarSlot in highlitSlots).color)
- event.context.drawBorder(inventorySlot.x + sx,
- inventorySlot.y + sy,
- 16, 16, color(inventorySlot in highlitSlots).color)
+ event.context.drawBorder(
+ hotbarSlot.x + sx,
+ hotbarSlot.y + sy,
+ 16, 16, color(hotbarSlot in highlitSlots).color
+ )
+ event.context.drawBorder(
+ inventorySlot.x + sx,
+ inventorySlot.y + sy,
+ 16, 16, color(inventorySlot in highlitSlots).color
+ )
}
}
@@ -383,9 +417,11 @@ object SlotLocking : FirmamentFeature {
hovX + sx, hovY + sy,
me.shedaniel.math.Color.ofOpaque(0x00FF00)
)
- event.context.drawBorder(hoveredSlot.x + sx,
- hoveredSlot.y + sy,
- 16, 16, 0xFF00FF00u.toInt())
+ event.context.drawBorder(
+ hoveredSlot.x + sx,
+ hoveredSlot.y + sy,
+ 16, 16, 0xFF00FF00u.toInt()
+ )
}
}
diff --git a/src/main/kotlin/features/inventory/TimerInLore.kt b/src/main/kotlin/features/inventory/TimerInLore.kt
index cc1df9a..e939404 100644
--- a/src/main/kotlin/features/inventory/TimerInLore.kt
+++ b/src/main/kotlin/features/inventory/TimerInLore.kt
@@ -47,6 +47,7 @@ object TimerInLore {
appendValue(ChronoField.SECOND_OF_MINUTE, 2)
}),
AMERICAN("EEEE, MMM d h:mm a yyyy"),
+ RFCPrecise(DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss.SSS Z")),
;
constructor(block: DateTimeFormatterBuilder.() -> Unit)
diff --git a/src/main/kotlin/features/items/EtherwarpOverlay.kt b/src/main/kotlin/features/items/EtherwarpOverlay.kt
index b1f695a..f6ab1a2 100644
--- a/src/main/kotlin/features/items/EtherwarpOverlay.kt
+++ b/src/main/kotlin/features/items/EtherwarpOverlay.kt
@@ -19,6 +19,7 @@ object EtherwarpOverlay : FirmamentFeature {
object TConfig : ManagedConfig(identifier, Category.ITEMS) {
var etherwarpOverlay by toggle("etherwarp-overlay") { false }
+ var onlyShowWhileSneaking by toggle("only-show-while-sneaking") { true }
var cube by toggle("cube") { true }
val cubeColour by colour("cube-colour") { ChromaColour.fromStaticRGB(172, 0, 255, 60) }
var wireframe by toggle("wireframe") { false }
@@ -32,7 +33,7 @@ object EtherwarpOverlay : FirmamentFeature {
fun renderEtherwarpOverlay(event: WorldRenderLastEvent) {
if (!TConfig.etherwarpOverlay) return
val player = MC.player ?: return
- if (!player.isSneaking) return
+ if (TConfig.onlyShowWhileSneaking && !player.isSneaking) return
val world = player.world
val camera = MC.camera ?: return
val heldItem = MC.stackInHand
diff --git a/src/main/kotlin/features/macros/RadialMenu.kt b/src/main/kotlin/features/macros/RadialMenu.kt
index 2e09c44..9e5222f 100644
--- a/src/main/kotlin/features/macros/RadialMenu.kt
+++ b/src/main/kotlin/features/macros/RadialMenu.kt
@@ -36,7 +36,11 @@ object RadialMenuViewer {
var activeMenu: RadialMenu? = null
set(value) {
- field = value
+ if (value?.options.isNullOrEmpty()) {
+ field = null
+ } else {
+ field = value
+ }
delta = Vector2f(0F, 0F)
}
var delta = Vector2f(0F, 0F)
diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt
index df89092..c3d1c52 100644
--- a/src/main/kotlin/repo/RepoManager.kt
+++ b/src/main/kotlin/repo/RepoManager.kt
@@ -7,7 +7,9 @@ import io.github.moulberry.repo.data.NEURecipe
import io.github.moulberry.repo.data.Rarity
import java.nio.file.Path
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import net.minecraft.client.MinecraftClient
import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket
import net.minecraft.recipe.display.CuttingRecipeDisplay
@@ -35,11 +37,13 @@ object RepoManager {
branch = "master"
save()
}
-
+ val enableREI by toggle("enable-rei") { true }
val disableItemGroups by toggle("disable-item-groups") { true }
val reload by button("reload") {
save()
- RepoManager.reload()
+ Firmament.coroutineScope.launch {
+ RepoManager.reload()
+ }
}
val redownload by button("redownload") {
save()
@@ -56,6 +60,9 @@ object RepoManager {
RENDER_AND_TEXT("text"),
;
+ fun rendersPerfectText() = this == RENDER_AND_TEXT
+ fun rendersPerfectVisuals() = this == RENDER || this == RENDER_AND_TEXT
+
override fun asString(): String? = label
}
@@ -131,16 +138,17 @@ object RepoManager {
fun reloadForTest(from: Path) {
neuRepo = makeNEURepository(from)
- reload()
+ reloadSync()
}
- fun reload() {
- if (!TestUtil.isInTest && !MC.instance.isOnThread) {
- MC.instance.send {
- reload()
- }
- return
+
+ suspend fun reload() {
+ withContext(Dispatchers.IO) {
+ reloadSync()
}
+ }
+
+ fun reloadSync() {
try {
logger.info("Repo reload started.")
neuRepo.reload()
@@ -168,7 +176,9 @@ object RepoManager {
if (Config.autoUpdate) {
launchAsyncUpdate()
} else {
- reload()
+ Firmament.coroutineScope.launch {
+ reload()
+ }
}
}
@@ -196,4 +206,6 @@ object RepoManager {
fun getRepoRef(): String {
return "${Config.username}/${Config.reponame}#${Config.branch}"
}
+
+ fun shouldLoadREI(): Boolean = Config.enableREI
}
diff --git a/src/main/kotlin/util/render/LerpUtils.kt b/src/main/kotlin/util/render/LerpUtils.kt
index 63a13ec..e7f226c 100644
--- a/src/main/kotlin/util/render/LerpUtils.kt
+++ b/src/main/kotlin/util/render/LerpUtils.kt
@@ -1,11 +1,15 @@
package moe.nea.firmament.util.render
import me.shedaniel.math.Color
+import kotlin.math.absoluteValue
val π = Math.PI
val τ = Math.PI * 2
-fun lerpAngle(a: Float, b: Float, progress: Float): Float {
+fun lerpAngle(a: Float, b: Float, progress: Float): Float {
// TODO: there is at least 10 mods to many in here lol
+ if (((b - a).absoluteValue - π).absoluteValue < 0.0001) {
+ return lerp(a, b, progress)
+ }
val shortestAngle = ((((b.mod(τ) - a.mod(τ)).mod(τ)) + τ + π).mod(τ)) - π
return ((a + (shortestAngle) * progress).mod(τ)).toFloat()
}
diff --git a/src/main/kotlin/util/skyblock/SkyBlockItems.kt b/src/main/kotlin/util/skyblock/SkyBlockItems.kt
index 4f208dd..d552fd7 100644
--- a/src/main/kotlin/util/skyblock/SkyBlockItems.kt
+++ b/src/main/kotlin/util/skyblock/SkyBlockItems.kt
@@ -19,4 +19,5 @@ object SkyBlockItems {
val BONE_BOOMERANG = SkyblockId("BONE_BOOMERANG")
val STARRED_BONE_BOOMERANG = SkyblockId("STARRED_BONE_BOOMERANG")
val TRIBAL_SPEAR = SkyblockId("TRIBAL_SPEAR")
+ val HUNTING_TOOLKIT = SkyblockId("HUNTING_TOOLKIT")
}
diff --git a/src/main/resources/firmament.accesswidener b/src/main/resources/firmament.accesswidener
index 71f63ac..0b7b830 100644
--- a/src/main/resources/firmament.accesswidener
+++ b/src/main/resources/firmament.accesswidener
@@ -16,6 +16,11 @@ accessible method net/minecraft/entity/decoration/ArmorStandEntity setSmall (Z)V
accessible method net/minecraft/resource/NamespaceResourceManager loadMetadata (Lnet/minecraft/resource/InputSupplier;)Lnet/minecraft/resource/metadata/ResourceMetadata;
accessible method net/minecraft/client/gui/DrawContext drawTexturedQuad (Ljava/util/function/Function;Lnet/minecraft/util/Identifier;IIIIFFFFI)V
+accessible class net/minecraft/client/render/model/BlockStatesLoader$LoadedBlockStateDefinition
+accessible field net/minecraft/client/render/model/BlockStatesLoader FINDER Lnet/minecraft/resource/ResourceFinder;
+accessible method net/minecraft/client/render/model/BlockStatesLoader$LoadedBlockStateDefinition <init> (Ljava/lang/String;Lnet/minecraft/client/render/model/json/BlockModelDefinition;)V
+accessible method net/minecraft/client/render/model/BlockStatesLoader combine (Lnet/minecraft/util/Identifier;Lnet/minecraft/state/StateManager;Ljava/util/List;)Lnet/minecraft/client/render/model/BlockStatesLoader$LoadedModels;
+
mutable field net/minecraft/screen/slot/Slot x I
mutable field net/minecraft/screen/slot/Slot y I
diff --git a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt
index 462b1e1..2d7a978 100644
--- a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt
+++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt
@@ -2,6 +2,9 @@
package moe.nea.firmament.features.texturepack
+import com.google.gson.JsonParseException
+import com.google.gson.JsonParser
+import com.mojang.serialization.JsonOps
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executor
import java.util.function.Function
@@ -21,15 +24,21 @@ import kotlinx.serialization.serializer
import kotlin.jvm.optionals.getOrNull
import net.minecraft.block.Block
import net.minecraft.block.BlockState
+import net.minecraft.block.Blocks
import net.minecraft.client.render.model.Baker
import net.minecraft.client.render.model.BlockStateModel
+import net.minecraft.client.render.model.BlockStatesLoader
import net.minecraft.client.render.model.ReferencedModelsCollector
import net.minecraft.client.render.model.SimpleBlockStateModel
+import net.minecraft.client.render.model.json.BlockModelDefinition
import net.minecraft.client.render.model.json.ModelVariant
+import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
+import net.minecraft.resource.Resource
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.SinglePreparationResourceReloader
+import net.minecraft.state.StateManager
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import net.minecraft.util.profiler.Profiler
@@ -41,6 +50,7 @@ import moe.nea.firmament.events.FinalizeResourceManagerEvent
import moe.nea.firmament.events.SkyblockServerUpdateEvent
import moe.nea.firmament.features.texturepack.CustomBlockTextures.createBakedModels
import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger
+import moe.nea.firmament.util.ErrorUtil
import moe.nea.firmament.util.IdentifierSerializer
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.SBData
@@ -62,12 +72,28 @@ object CustomBlockTextures {
val block: Identifier,
val sound: Identifier?,
) {
+ fun replace(block: BlockState): BlockStateModel? {
+ blockStateMap?.let { return it[block] }
+ return blockModel
+ }
+
+ @Transient
+ lateinit var overridingBlock: Block
@Transient
val blockModelIdentifier get() = block.withPrefixedPath("block/")
/**
- * Guaranteed to be set after [BakedReplacements.modelBakingFuture] is complete.
+ * Guaranteed to be set after [BakedReplacements.modelBakingFuture] is complete, if [unbakedBlockStateMap] is set.
+ */
+ @Transient
+ var blockStateMap: Map<BlockState, BlockStateModel>? = null
+
+ @Transient
+ var unbakedBlockStateMap: Map<BlockState, BlockStateModel.UnbakedGrouped>? = null
+
+ /**
+ * Guaranteed to be set after [BakedReplacements.modelBakingFuture] is complete. Prefer [blockStateMap] if present.
*/
@Transient
lateinit var blockModel: BlockStateModel
@@ -139,7 +165,15 @@ object CustomBlockTextures {
data class LocationReplacements(
val lookup: Map<Block, List<BlockReplacement>>
- )
+ ) {
+ init {
+ lookup.forEach { (block, replacements) ->
+ for (replacement in replacements) {
+ replacement.replacement.overridingBlock = block
+ }
+ }
+ }
+ }
data class BlockReplacement(
val checks: List<Area>?,
@@ -213,7 +247,7 @@ object CustomBlockTextures {
@JvmStatic
fun getReplacementModel(block: BlockState, blockPos: BlockPos?): BlockStateModel? {
- return getReplacement(block, blockPos)?.blockModel
+ return getReplacement(block, blockPos)?.replace(block)
}
@JvmStatic
@@ -236,8 +270,12 @@ object CustomBlockTextures {
}
@Volatile
- var preparationFuture: CompletableFuture<BakedReplacements> = CompletableFuture.completedFuture(BakedReplacements(
- mapOf()))
+ @get:JvmStatic
+ var preparationFuture: CompletableFuture<BakedReplacements> = CompletableFuture.completedFuture(
+ BakedReplacements(
+ mapOf()
+ )
+ )
val insideFallbackCall = ThreadLocal.withInitial { 0 }
@@ -257,7 +295,8 @@ object CustomBlockTextures {
fun onEarlyReload(event: EarlyResourceReloadEvent) {
preparationFuture = CompletableFuture
.supplyAsync(
- { prepare(event.resourceManager) }, event.preparationExecutor)
+ { prepare(event.resourceManager) }, event.preparationExecutor
+ )
}
private fun prepare(manager: ResourceManager): BakedReplacements {
@@ -295,7 +334,7 @@ object CustomBlockTextures {
@Subscribe
fun onStart(event: FinalizeResourceManagerEvent) {
event.resourceManager.registerReloader(object :
- SinglePreparationResourceReloader<BakedReplacements>() {
+ SinglePreparationResourceReloader<BakedReplacements>() {
override fun prepare(manager: ResourceManager, profiler: Profiler): BakedReplacements {
return preparationFuture.join().also {
it.modelBakingFuture.join()
@@ -328,12 +367,28 @@ object CustomBlockTextures {
@JvmStatic
fun collectExtraModels(modelsCollector: ReferencedModelsCollector) {
preparationFuture.join().collectAllReplacements()
- .forEach { modelsCollector.resolve(simpleBlockModel(it.blockModelIdentifier)) }
+ .forEach {
+ modelsCollector.resolve(simpleBlockModel(it.blockModelIdentifier))
+ it.unbakedBlockStateMap?.values?.forEach {
+ modelsCollector.resolve(it)
+ }
+ }
}
@JvmStatic
fun createBakedModels(baker: Baker, executor: Executor): CompletableFuture<Void?> {
return preparationFuture.thenComposeAsync(Function { replacements ->
+ val allBlockStates = CompletableFuture.allOf(
+ *replacements.collectAllReplacements().filter { it.unbakedBlockStateMap != null }.map {
+ CompletableFuture.supplyAsync({
+ it.blockStateMap = it.unbakedBlockStateMap
+ ?.map {
+ it.key to it.value.bake(it.key, baker)
+ }
+ ?.toMap()
+ }, executor)
+ }.toList().toTypedArray()
+ )
val byModel = replacements.collectAllReplacements().groupBy { it.blockModelIdentifier }
val modelBakingTask = AsyncHelper.mapValues(byModel, { blockId, replacements ->
val unbakedModel = SimpleBlockStateModel.Unbaked(
@@ -344,7 +399,55 @@ object CustomBlockTextures {
it.blockModel = baked
}
}, executor)
- modelBakingTask.thenAcceptAsync { replacements.modelBakingFuture.complete(Unit) }
+ modelBakingTask.thenComposeAsync {
+ allBlockStates
+ }.thenAcceptAsync {
+ replacements.modelBakingFuture.complete(Unit)
+ }
}, executor)
}
+
+ @JvmStatic
+ fun collectExtraBlockStateMaps(
+ extra: BakedReplacements,
+ original: Map<Identifier, List<Resource>>,
+ stateManagers: Function<Identifier, StateManager<Block, BlockState>?>
+ ) {
+ extra.collectAllReplacements().forEach {
+ val blockId = Registries.BLOCK.getKey(it.overridingBlock).getOrNull()?.value ?: return@forEach
+ val allModels = mutableListOf<BlockStatesLoader.LoadedBlockStateDefinition>()
+ val stateManager = stateManagers.apply(blockId) ?: return@forEach
+ for (resource in original[BlockStatesLoader.FINDER.toResourcePath(it.block)] ?: return@forEach) {
+ try {
+ resource.reader.use { reader ->
+ val jsonElement = JsonParser.parseReader(reader)
+ val blockModelDefinition =
+ BlockModelDefinition.CODEC.parse(JsonOps.INSTANCE, jsonElement)
+ .getOrThrow { msg: String? -> JsonParseException(msg) }
+ allModels.add(
+ BlockStatesLoader.LoadedBlockStateDefinition(
+ resource.getPackId(),
+ blockModelDefinition
+ )
+ )
+ }
+ } catch (exception: Exception) {
+ ErrorUtil.softError(
+ "Failed to load custom blockstate definition ${it.block} from pack ${resource.packId}",
+ exception
+ )
+ }
+ }
+
+ try {
+ it.unbakedBlockStateMap = BlockStatesLoader.combine(
+ blockId,
+ stateManager,
+ allModels
+ ).models
+ } catch (exception: Exception) {
+ ErrorUtil.softError("Failed to combine custom blockstate definitions for ${it.block}", exception)
+ }
+ }
+ }
}
diff --git a/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/LoadExtraBlockStates.java b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/LoadExtraBlockStates.java
new file mode 100644
index 0000000..c33fd04
--- /dev/null
+++ b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/LoadExtraBlockStates.java
@@ -0,0 +1,34 @@
+package moe.nea.firmament.mixins.custommodels;
+
+import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
+import com.llamalad7.mixinextras.sugar.Local;
+import moe.nea.firmament.features.texturepack.CustomBlockTextures;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockState;
+import net.minecraft.client.render.model.BlockStatesLoader;
+import net.minecraft.resource.Resource;
+import net.minecraft.state.StateManager;
+import net.minecraft.util.Identifier;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.function.Function;
+
+@Mixin(BlockStatesLoader.class)
+public class LoadExtraBlockStates {
+ @ModifyExpressionValue(method = "load", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;supplyAsync(Ljava/util/function/Supplier;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
+ private static CompletableFuture<Map<Identifier, List<Resource>>> loadExtraModels(
+ CompletableFuture<Map<Identifier, List<Resource>>> x,
+ @Local(argsOnly = true) Executor executor,
+ @Local Function<Identifier, StateManager<Block, BlockState>> stateManagers
+ ) {
+ return x.thenCombineAsync(CustomBlockTextures.getPreparationFuture(), (original, extra) -> {
+ CustomBlockTextures.collectExtraBlockStateMaps(extra, original, stateManagers);
+ return original;
+ }, executor);
+ }
+}