fix: Re-implement head_model with the new model format
This commit is contained in:
@@ -26,3 +26,5 @@ accessible method net/minecraft/client/render/RenderPhase$Texture getId ()Ljava/
|
||||
accessible field net/minecraft/client/render/RenderLayer$MultiPhase phases Lnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;
|
||||
accessible field net/minecraft/client/render/RenderLayer$MultiPhaseParameters texture Lnet/minecraft/client/render/RenderPhase$TextureBase;
|
||||
accessible field net/minecraft/client/network/ClientPlayerInteractionManager currentBreakingPos Lnet/minecraft/util/math/BlockPos;
|
||||
|
||||
mutable field net/minecraft/client/render/entity/state/LivingEntityRenderState headItemRenderState Lnet/minecraft/client/render/item/ItemRenderState;
|
||||
|
||||
@@ -110,6 +110,10 @@ object CustomModelOverrideParser {
|
||||
Firmament.identifier("predicates/legacy"),
|
||||
PredicateModel.Unbaked.CODEC
|
||||
)
|
||||
ItemModelTypes.ID_MAPPER.put(
|
||||
Firmament.identifier("head_model"),
|
||||
HeadModelChooser.Unbaked.CODEC
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package moe.nea.firmament.features.texturepack
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.client.item.ItemModelManager
|
||||
import net.minecraft.client.render.item.ItemRenderState
|
||||
import net.minecraft.client.render.item.model.BasicItemModel
|
||||
import net.minecraft.client.render.item.model.ItemModel
|
||||
import net.minecraft.client.render.item.model.ItemModelTypes
|
||||
import net.minecraft.client.render.model.ResolvableModel
|
||||
import net.minecraft.client.world.ClientWorld
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.ModelTransformationMode
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object HeadModelChooser {
|
||||
val IS_CHOOSING_HEAD_MODEL = ThreadLocal.withInitial { false }
|
||||
|
||||
interface HasExplicitHeadModelMarker {
|
||||
fun markExplicitHead_Firmament()
|
||||
fun isExplicitHeadModel_Firmament(): Boolean
|
||||
companion object{
|
||||
@JvmStatic
|
||||
fun cast(state: ItemRenderState) = state as HasExplicitHeadModelMarker
|
||||
}
|
||||
}
|
||||
|
||||
data class Baked(val head: ItemModel, val regular: ItemModel) : ItemModel {
|
||||
override fun update(
|
||||
state: ItemRenderState,
|
||||
stack: ItemStack?,
|
||||
resolver: ItemModelManager?,
|
||||
transformationMode: ModelTransformationMode?,
|
||||
world: ClientWorld?,
|
||||
user: LivingEntity?,
|
||||
seed: Int
|
||||
) {
|
||||
val instance =
|
||||
if (IS_CHOOSING_HEAD_MODEL.get()) {
|
||||
HasExplicitHeadModelMarker.cast(state).markExplicitHead_Firmament()
|
||||
head
|
||||
} else {
|
||||
regular
|
||||
}
|
||||
instance.update(state, stack, resolver, transformationMode, world, user, seed)
|
||||
}
|
||||
}
|
||||
|
||||
data class Unbaked(
|
||||
val head: ItemModel.Unbaked,
|
||||
val regular: ItemModel.Unbaked,
|
||||
) : ItemModel.Unbaked {
|
||||
override fun getCodec(): MapCodec<out ItemModel.Unbaked> {
|
||||
return CODEC
|
||||
}
|
||||
|
||||
override fun bake(context: ItemModel.BakeContext): ItemModel {
|
||||
return Baked(
|
||||
head.bake(context),
|
||||
regular.bake(context)
|
||||
)
|
||||
}
|
||||
|
||||
override fun resolve(resolver: ResolvableModel.Resolver) {
|
||||
head.resolve(resolver)
|
||||
regular.resolve(resolver)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromLegacyJson(jsonObject: JsonObject, unbakedModel: ItemModel.Unbaked): ItemModel.Unbaked {
|
||||
val model = jsonObject["firmament:head_model"] ?: return unbakedModel
|
||||
val modelUrl = model.asJsonPrimitive.asString
|
||||
val headModel = BasicItemModel.Unbaked(Identifier.of(modelUrl), listOf())
|
||||
return Unbaked(headModel, unbakedModel)
|
||||
}
|
||||
|
||||
val CODEC = RecordCodecBuilder.mapCodec {
|
||||
it.group(
|
||||
ItemModelTypes.CODEC.fieldOf("head")
|
||||
.forGetter(Unbaked::head),
|
||||
ItemModelTypes.CODEC.fieldOf("regular")
|
||||
.forGetter(Unbaked::regular),
|
||||
).apply(it, ::Unbaked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package moe.nea.firmament.mixins.custommodels;
|
||||
|
||||
import moe.nea.firmament.features.texturepack.HeadModelChooser;
|
||||
import net.minecraft.client.render.item.ItemRenderState;
|
||||
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;
|
||||
|
||||
@Mixin(ItemRenderState.class)
|
||||
public class ItemRenderStateExtraInfo implements HeadModelChooser.HasExplicitHeadModelMarker {
|
||||
boolean hasExplicitHead_firmament = false;
|
||||
|
||||
@Inject(method = "clear", at = @At("HEAD"))
|
||||
private void clear(CallbackInfo ci) {
|
||||
hasExplicitHead_firmament = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markExplicitHead_Firmament() {
|
||||
hasExplicitHead_firmament = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExplicitHeadModel_Firmament() {
|
||||
return hasExplicitHead_firmament;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package moe.nea.firmament.mixins.custommodels;
|
||||
|
||||
import moe.nea.firmament.features.texturepack.HeadModelChooser;
|
||||
import net.minecraft.client.item.ItemModelManager;
|
||||
import net.minecraft.client.render.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.render.entity.model.EntityModel;
|
||||
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
|
||||
import net.minecraft.client.render.item.ItemRenderState;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.ModelTransformationMode;
|
||||
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;
|
||||
|
||||
@Mixin(LivingEntityRenderer.class)
|
||||
public class ReplaceHeadModel<T extends LivingEntity, S extends LivingEntityRenderState, M extends EntityModel<? super S>> {
|
||||
@Shadow
|
||||
@Final
|
||||
protected ItemModelManager itemModelResolver;
|
||||
|
||||
@Unique
|
||||
private ItemRenderState tempRenderState = new ItemRenderState();
|
||||
|
||||
@Inject(
|
||||
method = "updateRenderState(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/client/render/entity/state/LivingEntityRenderState;F)V",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private void replaceHeadModel(
|
||||
T livingEntity, S livingEntityRenderState, float f, CallbackInfo ci
|
||||
) {
|
||||
var headItemStack = livingEntity.getEquippedStack(EquipmentSlot.HEAD);
|
||||
|
||||
HeadModelChooser.INSTANCE.getIS_CHOOSING_HEAD_MODEL().set(true);
|
||||
tempRenderState.clear();
|
||||
this.itemModelResolver.updateForLivingEntity(tempRenderState, headItemStack, ModelTransformationMode.HEAD, false, livingEntity);
|
||||
HeadModelChooser.INSTANCE.getIS_CHOOSING_HEAD_MODEL().set(false);
|
||||
|
||||
if (HeadModelChooser.HasExplicitHeadModelMarker.cast(tempRenderState)
|
||||
.isExplicitHeadModel_Firmament()) {
|
||||
livingEntityRenderState.wearingSkullType = null;
|
||||
var temp = livingEntityRenderState.headItemRenderState;
|
||||
livingEntityRenderState.headItemRenderState = tempRenderState;
|
||||
tempRenderState = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import moe.nea.firmament.Firmament;
|
||||
import moe.nea.firmament.features.texturepack.CustomSkyBlockTextures;
|
||||
import moe.nea.firmament.features.texturepack.HeadModelChooser;
|
||||
import moe.nea.firmament.features.texturepack.PredicateModel;
|
||||
import moe.nea.firmament.util.ErrorUtil;
|
||||
import net.minecraft.client.item.ItemAsset;
|
||||
@@ -61,6 +62,7 @@ public class SupplyFakeModelPatch {
|
||||
try (var is = resource.getInputStream()) {
|
||||
var jsonObject = Firmament.INSTANCE.getGson().fromJson(new InputStreamReader(is), JsonObject.class);
|
||||
unbakedModel = PredicateModel.Unbaked.fromLegacyJson(jsonObject, unbakedModel);
|
||||
unbakedModel = HeadModelChooser.Unbaked.fromLegacyJson(jsonObject, unbakedModel);
|
||||
} catch (Exception e) {
|
||||
ErrorUtil.INSTANCE.softError("Could not create resource for fake model supplication: " + model.getKey(), e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user