fix: Fix (some) parts of custom block rendering.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import com.google.common.hash.Hashing
|
||||
import com.google.devtools.ksp.gradle.KspAATask
|
||||
import com.google.devtools.ksp.gradle.KspTaskJvm
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
@@ -32,7 +33,7 @@ plugins {
|
||||
id("fabric-loom") version "1.10.1"
|
||||
alias(libs.plugins.shadow)
|
||||
id("moe.nea.licenseextractificator")
|
||||
id("moe.nea.mc-auto-translations") version "0.2.0"
|
||||
alias(libs.plugins.mcAutoTranslations)
|
||||
}
|
||||
|
||||
version = getGitTagInfo(libs.versions.minecraft.get())
|
||||
@@ -139,8 +140,10 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name", isEnabl
|
||||
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("ksp${upperName}Kotlin", KspAATask::class) {
|
||||
this.commandLineArgumentProviders.add { // TODO: update https://github.com/google/ksp/issues/2075
|
||||
listOf("firmament.sourceset=${ss.name}")
|
||||
}
|
||||
}
|
||||
tasks.named("compile${upperName}Kotlin", KotlinCompile::class) {
|
||||
this.enabled = isEnabled
|
||||
@@ -231,7 +234,7 @@ val jadeSourceSet = createIsolatedSourceSet("jade", isEnabled = false)
|
||||
val modmenuSourceSet = createIsolatedSourceSet("modmenu")
|
||||
val reiSourceSet = createIsolatedSourceSet("rei", isEnabled = false)
|
||||
val moulconfigSourceSet = createIsolatedSourceSet("moulconfig")
|
||||
val customTexturesSourceSet = createIsolatedSourceSet("texturePacks", "texturePacks", isEnabled = false)
|
||||
val customTexturesSourceSet = createIsolatedSourceSet("texturePacks", "texturePacks")
|
||||
|
||||
dependencies {
|
||||
// Minecraft dependencies
|
||||
|
||||
@@ -6,20 +6,21 @@
|
||||
minecraft = "1.21.5"
|
||||
|
||||
# Update from https://kotlinlang.org/
|
||||
kotlin = "2.1.10"
|
||||
kotlin = "2.1.20"
|
||||
# Update from https://github.com/google/ksp/releases
|
||||
kotlin_ksp = "2.1.10-1.0.30"
|
||||
kotlin_ksp = "2.1.20-2.0.0"
|
||||
|
||||
# Update from https://linkie.shedaniel.me/dependencies?loader=fabric
|
||||
fabric_loader = "0.16.10"
|
||||
fabric_api = "0.119.5+1.21.5"
|
||||
fabric_loader = "0.16.13"
|
||||
fabric_api = "0.119.9+1.21.5"
|
||||
yarn = "1.21.5+build.1"
|
||||
modmenu = "14.0.0-rc.2"
|
||||
architectury = "16.0.3"
|
||||
# Update from https://maven.architectury.dev/me/shedaniel/RoughlyEnoughItems-fabric/ (but is typically late)
|
||||
rei = "18.0.796"
|
||||
|
||||
# Update from https://maven.fabricmc.net/net/fabricmc/fabric-language-kotlin/
|
||||
fabric_kotlin = "1.13.1+kotlin.2.1.10"
|
||||
fabric_kotlin = "1.13.2+kotlin.2.1.20"
|
||||
|
||||
# Update from https://maven.architectury.dev/dev/architectury/loom/dev.architectury.loom.gradle.plugin/
|
||||
loom = "1.7.414" # TODO: port back to architectury (and) 1.9.424
|
||||
@@ -28,10 +29,10 @@ loom = "1.7.414" # TODO: port back to architectury (and) 1.9.424
|
||||
qolify = "1.6.0-1.21.1"
|
||||
|
||||
# Update from https://modrinth.com/mod/sodium/versions?l=fabric
|
||||
sodium = "mc1.21.5-0.6.11-fabric"
|
||||
sodium = "mc1.21.5-0.6.13-fabric"
|
||||
|
||||
# Update from https://modrinth.com/mod/freecam/versions?l=fabric
|
||||
freecammod = "1.3.2+mc1.21.4"
|
||||
freecammod = "1.3.3+mc1.21.5"
|
||||
|
||||
# Update from https://modrinth.com/mod/no-chat-reports/versions?l=fabric
|
||||
ncr = "Fabric-1.21.5-v2.12.0"
|
||||
@@ -43,18 +44,18 @@ femalegender = "4.3.3+1.21.4"
|
||||
explosiveenhancement = "1.2.3-1.21.0"
|
||||
|
||||
# Update from https://modrinth.com/mod/not-enough-animations/versions?l=fabric
|
||||
notenoughanimations = "eZykTicT"
|
||||
notenoughanimations = "prj4BdjU"
|
||||
|
||||
# Update from https://modrinth.com/mod/cit-resewn/versions?l=fabric
|
||||
citresewn = "1.2.0+1.21"
|
||||
|
||||
# Update from https://modrinth.com/mod/jade/versions?l=fabric
|
||||
jade = "17.2.2+fabric"
|
||||
jade = "18.1.0+fabric"
|
||||
|
||||
devauth = "1.2.1"
|
||||
|
||||
# Update from https://ktor.io/
|
||||
ktor = "3.0.3"
|
||||
# Update from https://ktor.io/docs/
|
||||
ktor = "3.1.2"
|
||||
|
||||
# Update from https://repo.nea.moe/#/releases/moe/nea/neurepoparser
|
||||
neurepoparser = "1.7.0"
|
||||
@@ -72,10 +73,13 @@ nealisp = "1.1.0"
|
||||
# Update from https://github.com/NotEnoughUpdates/MoulConfig/tags
|
||||
moulconfig = "3.3.0"
|
||||
|
||||
# Update from https://repo.nea.moe/#/releases/moe/nea/mc-auto-translations/moe.nea.mc-auto-translations.gradle.plugin
|
||||
mcAutoTranslations = "0.3.0"
|
||||
|
||||
# Update from https://www.curseforge.com/minecraft/mc-mods/configured/files/all?page=1&pageSize=20
|
||||
configured = "6023970"
|
||||
|
||||
# Update from https://modrinth.com/mod/hypixel-mod-api/versions
|
||||
# Update from https://modrinth.com/mod/hypixel-mod-api/versions?l=fabric
|
||||
hypixelmodapi = "1.0.1"
|
||||
hypixelmodapi_fabric = "1.0.1+build.1+mc1.21"
|
||||
|
||||
@@ -86,14 +90,14 @@ manninghamMills = "2.4.1"
|
||||
# Nvm, they just don't update docs: https://modrinth.com/mod/yacl/versions?l=fabric
|
||||
yacl = "3.6.6+1.21.5-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/
|
||||
basicMath = "0.6.1"
|
||||
|
||||
# Update from https://mvnrepository.com/artifact/net.lenni0451.classtransform/core
|
||||
classtransform = "1.14.0"
|
||||
classtransform = "1.14.1"
|
||||
|
||||
# Update from https://mvnrepository.com/artifact/org.ow2.asm/asm/
|
||||
asm = "9.7.1"
|
||||
asm = "9.8"
|
||||
|
||||
[libraries]
|
||||
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
||||
@@ -159,3 +163,4 @@ kotlin_plugin_powerassert = { id = "org.jetbrains.kotlin.plugin.power-assert", v
|
||||
kotlin_plugin_ksp = { id = "com.google.devtools.ksp", version.ref = "kotlin_ksp" }
|
||||
loom = { id = "dev.architectury.loom", version.ref = "loom" }
|
||||
shadow = { id = "com.github.johnrengelman.shadow", version = "8.1.1" }
|
||||
mcAutoTranslations = { id = "moe.nea.mc-auto-translations", version.ref = "mcAutoTranslations" }
|
||||
|
||||
@@ -6,6 +6,8 @@ accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARA
|
||||
accessible field net/minecraft/client/network/ClientPlayNetworkHandler combinedDynamicRegistries Lnet/minecraft/registry/DynamicRegistryManager$Immutable;
|
||||
accessible method net/minecraft/registry/RegistryOps <init> (Lcom/mojang/serialization/DynamicOps;Lnet/minecraft/registry/RegistryOps$RegistryInfoGetter;)V
|
||||
accessible class net/minecraft/registry/RegistryOps$CachedRegistryInfoGetter
|
||||
accessible class net/minecraft/client/render/model/ModelBaker$BakerImpl
|
||||
accessible method net/minecraft/client/render/model/ModelBaker$BakerImpl <init> (Lnet/minecraft/client/render/model/ModelBaker;Lnet/minecraft/client/render/model/ErrorCollectingSpriteGetter;)V
|
||||
|
||||
accessible field net/minecraft/entity/mob/CreeperEntity CHARGED Lnet/minecraft/entity/data/TrackedData;
|
||||
accessible method net/minecraft/entity/decoration/ArmorStandEntity setSmall (Z)V
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
package moe.nea.firmament.features.texturepack
|
||||
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.function.Function
|
||||
import net.fabricmc.loader.api.FabricLoader
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
@@ -19,8 +21,10 @@ import kotlinx.serialization.serializer
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.client.render.item.model.ItemModel
|
||||
import net.minecraft.client.render.model.Baker
|
||||
import net.minecraft.client.render.model.BlockStateModel
|
||||
import net.minecraft.client.render.model.SimpleBlockStateModel
|
||||
import net.minecraft.client.render.model.json.ModelVariant
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.resource.ResourceManager
|
||||
@@ -28,11 +32,13 @@ import net.minecraft.resource.SinglePreparationResourceReloader
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.profiler.Profiler
|
||||
import net.minecraft.util.thread.AsyncHelper
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.EarlyResourceReloadEvent
|
||||
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.IdentifierSerializer
|
||||
import moe.nea.firmament.util.MC
|
||||
@@ -43,244 +49,279 @@ import moe.nea.firmament.util.json.SingletonSerializableList
|
||||
|
||||
|
||||
object CustomBlockTextures {
|
||||
@Serializable
|
||||
data class CustomBlockOverride(
|
||||
val modes: @Serializable(SingletonSerializableList::class) List<String>,
|
||||
val area: List<Area>? = null,
|
||||
val replacements: Map<Identifier, Replacement>,
|
||||
)
|
||||
@Serializable
|
||||
data class CustomBlockOverride(
|
||||
val modes: @Serializable(SingletonSerializableList::class) List<String>,
|
||||
val area: List<Area>? = null,
|
||||
val replacements: Map<Identifier, Replacement>,
|
||||
)
|
||||
|
||||
@Serializable(with = Replacement.Serializer::class)
|
||||
data class Replacement(
|
||||
val block: Identifier,
|
||||
val sound: Identifier?,
|
||||
) {
|
||||
@Serializable(with = Replacement.Serializer::class)
|
||||
data class Replacement(
|
||||
val block: Identifier,
|
||||
val sound: Identifier?,
|
||||
) {
|
||||
|
||||
@Transient
|
||||
val blockModelIdentifier get() = block.withPrefixedPath("block/")
|
||||
@Transient
|
||||
val blockModelIdentifier get() = block.withPrefixedPath("block/")
|
||||
|
||||
@Transient
|
||||
val bakedModel: ItemModel by lazy(LazyThreadSafetyMode.NONE) {
|
||||
MC.instance.bakedModelManager.blockModels.(blockModelIdentifier)
|
||||
}
|
||||
/**
|
||||
* Guaranteed to be set after [BakedReplacements.modelBakingFuture] is complete.
|
||||
*/
|
||||
@Transient
|
||||
lateinit var blockModel: BlockStateModel
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@kotlinx.serialization.Serializer(Replacement::class)
|
||||
object DefaultSerializer : KSerializer<Replacement>
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@kotlinx.serialization.Serializer(Replacement::class)
|
||||
object DefaultSerializer : KSerializer<Replacement>
|
||||
|
||||
object Serializer : KSerializer<Replacement> {
|
||||
val delegate = serializer<JsonElement>()
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = delegate.descriptor
|
||||
object Serializer : KSerializer<Replacement> {
|
||||
val delegate = serializer<JsonElement>()
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = delegate.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): Replacement {
|
||||
val jsonElement = decoder.decodeSerializableValue(delegate)
|
||||
if (jsonElement is JsonPrimitive) {
|
||||
require(jsonElement.isString)
|
||||
return Replacement(Identifier.tryParse(jsonElement.content)!!, null)
|
||||
}
|
||||
return (decoder as JsonDecoder).json.decodeFromJsonElement(DefaultSerializer, jsonElement)
|
||||
}
|
||||
override fun deserialize(decoder: Decoder): Replacement {
|
||||
val jsonElement = decoder.decodeSerializableValue(delegate)
|
||||
if (jsonElement is JsonPrimitive) {
|
||||
require(jsonElement.isString)
|
||||
return Replacement(Identifier.tryParse(jsonElement.content)!!, null)
|
||||
}
|
||||
return (decoder as JsonDecoder).json.decodeFromJsonElement(DefaultSerializer, jsonElement)
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Replacement) {
|
||||
encoder.encodeSerializableValue(DefaultSerializer, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun serialize(encoder: Encoder, value: Replacement) {
|
||||
encoder.encodeSerializableValue(DefaultSerializer, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Area(
|
||||
val min: BlockPos,
|
||||
val max: BlockPos,
|
||||
) {
|
||||
@Transient
|
||||
val realMin = BlockPos(
|
||||
minOf(min.x, max.x),
|
||||
minOf(min.y, max.y),
|
||||
minOf(min.z, max.z),
|
||||
)
|
||||
@Serializable
|
||||
data class Area(
|
||||
val min: BlockPos,
|
||||
val max: BlockPos,
|
||||
) {
|
||||
@Transient
|
||||
val realMin = BlockPos(
|
||||
minOf(min.x, max.x),
|
||||
minOf(min.y, max.y),
|
||||
minOf(min.z, max.z),
|
||||
)
|
||||
|
||||
@Transient
|
||||
val realMax = BlockPos(
|
||||
maxOf(min.x, max.x),
|
||||
maxOf(min.y, max.y),
|
||||
maxOf(min.z, max.z),
|
||||
)
|
||||
@Transient
|
||||
val realMax = BlockPos(
|
||||
maxOf(min.x, max.x),
|
||||
maxOf(min.y, max.y),
|
||||
maxOf(min.z, max.z),
|
||||
)
|
||||
|
||||
fun roughJoin(other: Area): Area {
|
||||
return Area(
|
||||
BlockPos(
|
||||
minOf(realMin.x, other.realMin.x),
|
||||
minOf(realMin.y, other.realMin.y),
|
||||
minOf(realMin.z, other.realMin.z),
|
||||
),
|
||||
BlockPos(
|
||||
maxOf(realMax.x, other.realMax.x),
|
||||
maxOf(realMax.y, other.realMax.y),
|
||||
maxOf(realMax.z, other.realMax.z),
|
||||
)
|
||||
)
|
||||
}
|
||||
fun roughJoin(other: Area): Area {
|
||||
return Area(
|
||||
BlockPos(
|
||||
minOf(realMin.x, other.realMin.x),
|
||||
minOf(realMin.y, other.realMin.y),
|
||||
minOf(realMin.z, other.realMin.z),
|
||||
),
|
||||
BlockPos(
|
||||
maxOf(realMax.x, other.realMax.x),
|
||||
maxOf(realMax.y, other.realMax.y),
|
||||
maxOf(realMax.z, other.realMax.z),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun contains(blockPos: BlockPos): Boolean {
|
||||
return (blockPos.x in realMin.x..realMax.x) &&
|
||||
(blockPos.y in realMin.y..realMax.y) &&
|
||||
(blockPos.z in realMin.z..realMax.z)
|
||||
}
|
||||
}
|
||||
fun contains(blockPos: BlockPos): Boolean {
|
||||
return (blockPos.x in realMin.x..realMax.x) &&
|
||||
(blockPos.y in realMin.y..realMax.y) &&
|
||||
(blockPos.z in realMin.z..realMax.z)
|
||||
}
|
||||
}
|
||||
|
||||
data class LocationReplacements(
|
||||
val lookup: Map<Block, List<BlockReplacement>>
|
||||
)
|
||||
data class LocationReplacements(
|
||||
val lookup: Map<Block, List<BlockReplacement>>
|
||||
)
|
||||
|
||||
data class BlockReplacement(
|
||||
val checks: List<Area>?,
|
||||
val replacement: Replacement,
|
||||
) {
|
||||
val roughCheck by lazy(LazyThreadSafetyMode.NONE) {
|
||||
if (checks == null || checks.size < 3) return@lazy null
|
||||
checks.reduce { acc, next -> acc.roughJoin(next) }
|
||||
}
|
||||
}
|
||||
data class BlockReplacement(
|
||||
val checks: List<Area>?,
|
||||
val replacement: Replacement,
|
||||
) {
|
||||
val roughCheck by lazy(LazyThreadSafetyMode.NONE) {
|
||||
if (checks == null || checks.size < 3) return@lazy null
|
||||
checks.reduce { acc, next -> acc.roughJoin(next) }
|
||||
}
|
||||
}
|
||||
|
||||
data class BakedReplacements(val data: Map<SkyBlockIsland, LocationReplacements>)
|
||||
data class BakedReplacements(val data: Map<SkyBlockIsland, LocationReplacements>) {
|
||||
/**
|
||||
* Fulfilled by [createBakedModels] which is called during model baking. Once completed, all [Replacement.blockModel] will be set.
|
||||
*/
|
||||
val modelBakingFuture = CompletableFuture<Unit>()
|
||||
|
||||
var allLocationReplacements: BakedReplacements = BakedReplacements(mapOf())
|
||||
var currentIslandReplacements: LocationReplacements? = null
|
||||
/**
|
||||
* @returns a list of all [Replacement]s.
|
||||
*/
|
||||
fun collectAllReplacements(): Sequence<Replacement> {
|
||||
return data.values.asSequence()
|
||||
.flatMap { it.lookup.values }
|
||||
.flatten()
|
||||
.map { it.replacement }
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshReplacements() {
|
||||
val location = SBData.skyblockLocation
|
||||
val replacements =
|
||||
if (CustomSkyBlockTextures.TConfig.enableBlockOverrides) location?.let(allLocationReplacements.data::get)
|
||||
else null
|
||||
val lastReplacements = currentIslandReplacements
|
||||
currentIslandReplacements = replacements
|
||||
if (lastReplacements != replacements) {
|
||||
MC.nextTick {
|
||||
MC.worldRenderer.chunks?.chunks?.forEach {
|
||||
// false schedules rebuilds outside a 27 block radius to happen async
|
||||
it.scheduleRebuild(false)
|
||||
}
|
||||
sodiumReloadTask?.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
var allLocationReplacements: BakedReplacements = BakedReplacements(mapOf())
|
||||
var currentIslandReplacements: LocationReplacements? = null
|
||||
|
||||
private val sodiumReloadTask = runCatching {
|
||||
val r = Class.forName("moe.nea.firmament.compat.sodium.SodiumChunkReloader")
|
||||
.getConstructor()
|
||||
.newInstance() as Runnable
|
||||
r.run()
|
||||
r
|
||||
}.getOrElse {
|
||||
if (FabricLoader.getInstance().isModLoaded("sodium"))
|
||||
logger.error("Could not create sodium chunk reloader")
|
||||
null
|
||||
}
|
||||
fun refreshReplacements() {
|
||||
val location = SBData.skyblockLocation
|
||||
val replacements =
|
||||
if (CustomSkyBlockTextures.TConfig.enableBlockOverrides) location?.let(allLocationReplacements.data::get)
|
||||
else null
|
||||
val lastReplacements = currentIslandReplacements
|
||||
currentIslandReplacements = replacements
|
||||
if (lastReplacements != replacements) {
|
||||
MC.nextTick {
|
||||
MC.worldRenderer.chunks?.chunks?.forEach {
|
||||
// false schedules rebuilds outside a 27 block radius to happen async
|
||||
it.scheduleRebuild(false)
|
||||
}
|
||||
sodiumReloadTask?.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val sodiumReloadTask = runCatching {
|
||||
val r = Class.forName("moe.nea.firmament.compat.sodium.SodiumChunkReloader")
|
||||
.getConstructor()
|
||||
.newInstance() as Runnable
|
||||
r.run()
|
||||
r
|
||||
}.getOrElse {
|
||||
if (FabricLoader.getInstance().isModLoaded("sodium"))
|
||||
logger.error("Could not create sodium chunk reloader")
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
fun matchesPosition(replacement: BlockReplacement, blockPos: BlockPos?): Boolean {
|
||||
if (blockPos == null) return true
|
||||
val rc = replacement.roughCheck
|
||||
if (rc != null && !rc.contains(blockPos)) return false
|
||||
val areas = replacement.checks
|
||||
if (areas != null && !areas.any { it.contains(blockPos) }) return false
|
||||
return true
|
||||
}
|
||||
fun matchesPosition(replacement: BlockReplacement, blockPos: BlockPos?): Boolean {
|
||||
if (blockPos == null) return true
|
||||
val rc = replacement.roughCheck
|
||||
if (rc != null && !rc.contains(blockPos)) return false
|
||||
val areas = replacement.checks
|
||||
if (areas != null && !areas.any { it.contains(blockPos) }) return false
|
||||
return true
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getReplacementModel(block: BlockState, blockPos: BlockPos?): BlockStateModel? {
|
||||
return getReplacement(block, blockPos)?.bakedModel
|
||||
}
|
||||
@JvmStatic
|
||||
fun getReplacementModel(block: BlockState, blockPos: BlockPos?): BlockStateModel? {
|
||||
return getReplacement(block, blockPos)?.blockModel
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getReplacement(block: BlockState, blockPos: BlockPos?): Replacement? {
|
||||
if (isInFallback() && blockPos == null) {
|
||||
return null
|
||||
}
|
||||
val replacements = currentIslandReplacements?.lookup?.get(block.block) ?: return null
|
||||
for (replacement in replacements) {
|
||||
if (replacement.checks == null || matchesPosition(replacement, blockPos))
|
||||
return replacement.replacement
|
||||
}
|
||||
return null
|
||||
}
|
||||
@JvmStatic
|
||||
fun getReplacement(block: BlockState, blockPos: BlockPos?): Replacement? {
|
||||
if (isInFallback() && blockPos == null) {
|
||||
return null
|
||||
}
|
||||
val replacements = currentIslandReplacements?.lookup?.get(block.block) ?: return null
|
||||
for (replacement in replacements) {
|
||||
if (replacement.checks == null || matchesPosition(replacement, blockPos))
|
||||
return replacement.replacement
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
fun onLocation(event: SkyblockServerUpdateEvent) {
|
||||
refreshReplacements()
|
||||
}
|
||||
@Subscribe
|
||||
fun onLocation(event: SkyblockServerUpdateEvent) {
|
||||
refreshReplacements()
|
||||
}
|
||||
|
||||
@Volatile
|
||||
var preparationFuture: CompletableFuture<BakedReplacements> = CompletableFuture.completedFuture(BakedReplacements(
|
||||
mapOf()))
|
||||
@Volatile
|
||||
var preparationFuture: CompletableFuture<BakedReplacements> = CompletableFuture.completedFuture(BakedReplacements(
|
||||
mapOf()))
|
||||
|
||||
val insideFallbackCall = ThreadLocal.withInitial { 0 }
|
||||
val insideFallbackCall = ThreadLocal.withInitial { 0 }
|
||||
|
||||
@JvmStatic
|
||||
fun enterFallbackCall() {
|
||||
insideFallbackCall.set(insideFallbackCall.get() + 1)
|
||||
}
|
||||
@JvmStatic
|
||||
fun enterFallbackCall() {
|
||||
insideFallbackCall.set(insideFallbackCall.get() + 1)
|
||||
}
|
||||
|
||||
fun isInFallback() = insideFallbackCall.get() > 0
|
||||
fun isInFallback() = insideFallbackCall.get() > 0
|
||||
|
||||
@JvmStatic
|
||||
fun exitFallbackCall() {
|
||||
insideFallbackCall.set(insideFallbackCall.get() - 1)
|
||||
}
|
||||
@JvmStatic
|
||||
fun exitFallbackCall() {
|
||||
insideFallbackCall.set(insideFallbackCall.get() - 1)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onEarlyReload(event: EarlyResourceReloadEvent) {
|
||||
preparationFuture = CompletableFuture
|
||||
.supplyAsync(
|
||||
{ prepare(event.resourceManager) }, event.preparationExecutor)
|
||||
}
|
||||
@Subscribe
|
||||
fun onEarlyReload(event: EarlyResourceReloadEvent) {
|
||||
preparationFuture = CompletableFuture
|
||||
.supplyAsync(
|
||||
{ prepare(event.resourceManager) }, event.preparationExecutor)
|
||||
}
|
||||
|
||||
private fun prepare(manager: ResourceManager): BakedReplacements {
|
||||
val resources = manager.findResources("overrides/blocks") {
|
||||
it.namespace == "firmskyblock" && it.path.endsWith(".json")
|
||||
}
|
||||
val map = mutableMapOf<SkyBlockIsland, MutableMap<Block, MutableList<BlockReplacement>>>()
|
||||
for ((file, resource) in resources) {
|
||||
val json =
|
||||
Firmament.tryDecodeJsonFromStream<CustomBlockOverride>(resource.inputStream)
|
||||
.getOrElse { ex ->
|
||||
logger.error("Failed to load block texture override at $file", ex)
|
||||
continue
|
||||
}
|
||||
for (mode in json.modes) {
|
||||
val island = SkyBlockIsland.forMode(mode)
|
||||
val islandMpa = map.getOrPut(island, ::mutableMapOf)
|
||||
for ((blockId, replacement) in json.replacements) {
|
||||
val block = MC.defaultRegistries.getOrThrow(RegistryKeys.BLOCK)
|
||||
.getOptional(RegistryKey.of(RegistryKeys.BLOCK, blockId))
|
||||
.getOrNull()
|
||||
if (block == null) {
|
||||
logger.error("Failed to load block texture override at ${file}: unknown block '$blockId'")
|
||||
continue
|
||||
}
|
||||
val replacements = islandMpa.getOrPut(block.value(), ::mutableListOf)
|
||||
replacements.add(BlockReplacement(json.area, replacement))
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun prepare(manager: ResourceManager): BakedReplacements {
|
||||
val resources = manager.findResources("overrides/blocks") {
|
||||
it.namespace == "firmskyblock" && it.path.endsWith(".json")
|
||||
}
|
||||
val map = mutableMapOf<SkyBlockIsland, MutableMap<Block, MutableList<BlockReplacement>>>()
|
||||
for ((file, resource) in resources) {
|
||||
val json =
|
||||
Firmament.tryDecodeJsonFromStream<CustomBlockOverride>(resource.inputStream)
|
||||
.getOrElse { ex ->
|
||||
logger.error("Failed to load block texture override at $file", ex)
|
||||
continue
|
||||
}
|
||||
for (mode in json.modes) {
|
||||
val island = SkyBlockIsland.forMode(mode)
|
||||
val islandMpa = map.getOrPut(island, ::mutableMapOf)
|
||||
for ((blockId, replacement) in json.replacements) {
|
||||
val block = MC.defaultRegistries.getOrThrow(RegistryKeys.BLOCK)
|
||||
.getOptional(RegistryKey.of(RegistryKeys.BLOCK, blockId))
|
||||
.getOrNull()
|
||||
if (block == null) {
|
||||
logger.error("Failed to load block texture override at ${file}: unknown block '$blockId'")
|
||||
continue
|
||||
}
|
||||
val replacements = islandMpa.getOrPut(block.value(), ::mutableListOf)
|
||||
replacements.add(BlockReplacement(json.area, replacement))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BakedReplacements(map.mapValues { LocationReplacements(it.value) })
|
||||
}
|
||||
return BakedReplacements(map.mapValues { LocationReplacements(it.value) })
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun onStart(event: FinalizeResourceManagerEvent) {
|
||||
event.resourceManager.registerReloader(object :
|
||||
SinglePreparationResourceReloader<BakedReplacements>() {
|
||||
override fun prepare(manager: ResourceManager, profiler: Profiler): BakedReplacements {
|
||||
return preparationFuture.join()
|
||||
}
|
||||
@Subscribe
|
||||
fun onStart(event: FinalizeResourceManagerEvent) {
|
||||
event.resourceManager.registerReloader(object :
|
||||
SinglePreparationResourceReloader<BakedReplacements>() {
|
||||
override fun prepare(manager: ResourceManager, profiler: Profiler): BakedReplacements {
|
||||
return preparationFuture.join().also {
|
||||
it.modelBakingFuture.join()
|
||||
}
|
||||
}
|
||||
|
||||
override fun apply(prepared: BakedReplacements, manager: ResourceManager, profiler: Profiler?) {
|
||||
allLocationReplacements = prepared
|
||||
refreshReplacements()
|
||||
}
|
||||
})
|
||||
}
|
||||
override fun apply(prepared: BakedReplacements, manager: ResourceManager, profiler: Profiler?) {
|
||||
allLocationReplacements = prepared
|
||||
refreshReplacements()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createBakedModels(baker: Baker, executor: Executor): CompletableFuture<Void?> {
|
||||
return preparationFuture.thenComposeAsync(Function { replacements ->
|
||||
val byModel = replacements.collectAllReplacements().groupBy { it.blockModelIdentifier }
|
||||
val modelBakingTask = AsyncHelper.mapValues(byModel, { blockId, replacements ->
|
||||
val unbakedModel = SimpleBlockStateModel.Unbaked(
|
||||
ModelVariant(blockId)
|
||||
) // TODO: do i need to resolve models here? Maybe this needs to be resolved earlier before baking.
|
||||
val baked = unbakedModel.bake(baker)
|
||||
replacements.forEach {
|
||||
it.blockModel = baked
|
||||
}
|
||||
}, executor)
|
||||
modelBakingTask.thenAcceptAsync { replacements.modelBakingFuture.complete(Unit) }
|
||||
}, executor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package moe.nea.firmament.mixins.custommodels;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import moe.nea.firmament.features.texturepack.CustomBlockTextures;
|
||||
import net.minecraft.client.render.model.Baker;
|
||||
import net.minecraft.client.render.model.ModelBaker;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Mixin(ModelBaker.class)
|
||||
public class BuildExtraBlockStateModels {
|
||||
@ModifyReturnValue(method = "bake", at = @At("RETURN"))
|
||||
private CompletableFuture<ModelBaker.BakedModels> injectMoreBlockModels(CompletableFuture<ModelBaker.BakedModels> original, @Local ModelBaker.BakerImpl baker, @Local(argsOnly = true) Executor executor) {
|
||||
Baker b = baker;
|
||||
return original.thenCombine(
|
||||
CustomBlockTextures.createBakedModels(b, executor),
|
||||
(a, _void) -> a
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,8 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import moe.nea.firmament.features.texturepack.CustomBlockTextures;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.block.BlockModels;
|
||||
import net.minecraft.client.render.block.BlockRenderManager;
|
||||
import net.minecraft.client.render.chunk.SectionBuilder;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BlockStateModel;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -16,24 +14,24 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(SectionBuilder.class)
|
||||
public class ReplaceBlockRenderManagerBlockModel {
|
||||
@WrapOperation(method = "build", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockRenderManager;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BlockStateModel;"))
|
||||
private BlockStateModel replaceModelInRenderBlock(BlockRenderManager instance, BlockState state, Operation<BlockStateModel> original, @Local(argsOnly = true) BlockPos pos) {
|
||||
var replacement = CustomBlockTextures.getReplacementModel(state, pos);
|
||||
if (replacement != null) return replacement;
|
||||
CustomBlockTextures.enterFallbackCall();
|
||||
var fallback = original.call(instance, state);
|
||||
CustomBlockTextures.exitFallbackCall();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@WrapOperation(method = "renderDamage", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModels;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;"))
|
||||
private BakedModel replaceModelInRenderDamage(
|
||||
BlockModels instance, BlockState state, Operation<BakedModel> original, @Local(argsOnly = true) BlockPos pos) {
|
||||
var replacement = CustomBlockTextures.getReplacementModel(state, pos);
|
||||
if (replacement != null) return replacement;
|
||||
CustomBlockTextures.enterFallbackCall();
|
||||
var fallback = original.call(instance, state);
|
||||
CustomBlockTextures.exitFallbackCall();
|
||||
return fallback;
|
||||
}
|
||||
@WrapOperation(method = "build", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockRenderManager;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BlockStateModel;"))
|
||||
private BlockStateModel replaceModelInRenderBlock(BlockRenderManager instance, BlockState state, Operation<BlockStateModel> original, @Local(ordinal = 2) BlockPos pos) {
|
||||
var replacement = CustomBlockTextures.getReplacementModel(state, pos);
|
||||
if (replacement != null) return replacement;
|
||||
CustomBlockTextures.enterFallbackCall();
|
||||
var fallback = original.call(instance, state);
|
||||
CustomBlockTextures.exitFallbackCall();
|
||||
return fallback;
|
||||
}
|
||||
//TODO: cover renderDamage model
|
||||
// @WrapOperation(method = "renderDamage", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/block/BlockModels;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;"))
|
||||
// private BakedModel replaceModelInRenderDamage(
|
||||
// BlockModels instance, BlockState state, Operation<BakedModel> original, @Local(argsOnly = true) BlockPos pos) {
|
||||
// var replacement = CustomBlockTextures.getReplacementModel(state, pos);
|
||||
// if (replacement != null) return replacement;
|
||||
// CustomBlockTextures.enterFallbackCall();
|
||||
// var fallback = original.call(instance, state);
|
||||
// CustomBlockTextures.exitFallbackCall();
|
||||
// return fallback;
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package moe.nea.firmament.mixins.custommodels;
|
||||
import moe.nea.firmament.features.texturepack.CustomBlockTextures;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.block.BlockModels;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BlockStateModel;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
public class ReplaceFallbackBlockModel {
|
||||
// TODO: add check to BlockDustParticle
|
||||
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
|
||||
private void getModel(BlockState state, CallbackInfoReturnable<BakedModel> cir) {
|
||||
private void getModel(BlockState state, CallbackInfoReturnable<BlockStateModel> cir) {
|
||||
var replacement = CustomBlockTextures.getReplacementModel(state, null);
|
||||
if (replacement != null)
|
||||
cir.setReturnValue(replacement);
|
||||
|
||||
@@ -25,7 +25,7 @@ class SubscribeAnnotationProcessor(
|
||||
override fun finish() {
|
||||
subscriptions.sort()
|
||||
if (subscriptions.isEmpty()) return
|
||||
val subscriptionSet = subscriptions.mapTo(mutableSetOf()) { it.parent.containingFile!! }
|
||||
val subscriptionSet = subscriptions.mapTo(mutableSetOf()) { it.cf }
|
||||
val dependencies = Dependencies(
|
||||
aggregating = true,
|
||||
*subscriptionSet.toTypedArray())
|
||||
@@ -38,7 +38,7 @@ class SubscribeAnnotationProcessor(
|
||||
appendLine("// This file is @generated by SubscribeAnnotationProcessor")
|
||||
appendLine("// Do not edit")
|
||||
for (file in subscriptionSet) {
|
||||
appendLine("// Dependency: ${file.filePath}")
|
||||
appendLine("// Dependency: ${"TODO"?:file.filePath}")
|
||||
}
|
||||
appendLine("package moe.nea.firmament.annotations.generated.$sourceSetName")
|
||||
appendLine()
|
||||
@@ -48,7 +48,7 @@ class SubscribeAnnotationProcessor(
|
||||
appendLine("class $generatedFileName : SubscriptionList {")
|
||||
appendLine(" override fun provideSubscriptions(addSubscription: (Subscription<*>) -> Unit) {")
|
||||
for (subscription in subscriptions) {
|
||||
val owner = subscription.parent.qualifiedName!!.asString()
|
||||
val owner = subscription.pQName.asString()
|
||||
val method = subscription.child.simpleName.asString()
|
||||
val type = subscription.type.declaration.qualifiedName!!.asString()
|
||||
appendLine(" addSubscription(Subscription<$type>(")
|
||||
@@ -75,13 +75,15 @@ class SubscribeAnnotationProcessor(
|
||||
val child: KSFunctionDeclaration,
|
||||
val type: KSType,
|
||||
) : Comparable<Subscription> {
|
||||
val cf = parent.containingFile!!
|
||||
val pQName = parent.qualifiedName!!
|
||||
val tName = type.declaration.qualifiedName!!
|
||||
override fun compareTo(other: Subscription): Int {
|
||||
var compare = parent.qualifiedName!!.asString().compareTo(other.parent.qualifiedName!!.asString())
|
||||
var compare = pQName.asString().compareTo(other.pQName.asString())
|
||||
if (compare != 0) return compare
|
||||
compare = other.child.simpleName.asString().compareTo(child.simpleName.asString())
|
||||
if (compare != 0) return compare
|
||||
compare = other.type.declaration.qualifiedName!!.asString()
|
||||
.compareTo(type.declaration.qualifiedName!!.asString())
|
||||
compare = other.tName.asString().compareTo(tName.asString())
|
||||
if (compare != 0) return compare
|
||||
return 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user