Merge branch '1.21.3' into 1.21.4

# Conflicts:
#	src/main/java/com/minelittlepony/client/render/entity/feature/ArmourFeature.java
This commit is contained in:
Sollace 2024-12-17 13:48:36 +01:00
commit 6b7b33958b
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
6 changed files with 109 additions and 8 deletions

@ -1 +1 @@
Subproject commit 1ae97d064e7579d94a93f2784473dc7ce0e1e670 Subproject commit 913c35681b09cfbab0bf5def678db3407f5834bb

View file

@ -77,6 +77,15 @@ public class PonyConfig extends Config {
.addComment("Disables certain easter eggs and secrets (party pooper)") .addComment("Disables certain easter eggs and secrets (party pooper)")
.addComment("Turning this off may help with compatibility in some cases"); .addComment("Turning this off may help with compatibility in some cases");
public final Setting<Boolean> enableFabricModelsApiSupport = value("settings", "enableFabricModelsApiSupport", false)
.addComment("Enables rendering of modded armour registered via the fabric api")
.addComment("Note that since any armour registered in this way is designed to work for the human model, pieces may not fit exactly.")
.addComment("i.e. Anything that goes on the plyer's backs needs to be rotated by the mod developer when rendered on a pony")
.addComment("Developers: To know if you're being rendered on a pony model, check the renderstate or model class with")
.addComment(" state instanceof com.minelittlepony.api.model.PonyModel$AttributedHolder or model instanceof com.minelittlepony.api.model.PonyModel")
.addComment(" Note that the matrix stack your receieve is pre-transformed for the body part your model is attached to, so if you intend to call model.transform(state, part, matrices)")
.addComment(" with a different part (ie BACK) you must pop the stack to revert to the previous first.");
public final Setting<VisibilityMode> horseButton = value("horseButton", VisibilityMode.AUTO) public final Setting<VisibilityMode> horseButton = value("horseButton", VisibilityMode.AUTO)
.addComment("Whether to show the mine little pony settings button on the main menu") .addComment("Whether to show the mine little pony settings button on the main menu")
.addComment("AUTO (default) - only show when HDSkins is not installed") .addComment("AUTO (default) - only show when HDSkins is not installed")

View file

@ -23,7 +23,6 @@ import com.minelittlepony.api.model.Models;
import com.minelittlepony.client.model.AbstractPonyModel; import com.minelittlepony.client.model.AbstractPonyModel;
import com.minelittlepony.client.model.ClientPonyModel; import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.render.entity.state.PonyRenderState; import com.minelittlepony.client.render.entity.state.PonyRenderState;
import java.util.*; import java.util.*;
public class PonifiedEquipmentRenderer extends EquipmentRenderer { public class PonifiedEquipmentRenderer extends EquipmentRenderer {

View file

@ -1,21 +1,31 @@
package com.minelittlepony.client.render.entity.feature; package com.minelittlepony.client.render.entity.feature;
import com.minelittlepony.api.model.Models; import com.minelittlepony.api.config.PonyConfig;
import com.minelittlepony.api.model.*;
import com.minelittlepony.client.model.ClientPonyModel; import com.minelittlepony.client.model.ClientPonyModel;
import com.minelittlepony.client.model.armour.*; import com.minelittlepony.client.model.armour.*;
import com.minelittlepony.client.render.PonyRenderContext; import com.minelittlepony.client.render.PonyRenderContext;
import com.minelittlepony.client.render.entity.state.PonyRenderState; import com.minelittlepony.client.render.entity.state.PonyRenderState;
import com.minelittlepony.client.util.render.MatrixStackUtil;
import java.util.*;
import net.fabricmc.fabric.api.client.rendering.v1.ArmorRenderer;
import net.fabricmc.fabric.impl.client.rendering.ArmorRendererRegistryImpl;
import net.minecraft.client.render.*; import net.minecraft.client.render.*;
import net.minecraft.client.render.entity.equipment.EquipmentModel; import net.minecraft.client.render.entity.equipment.EquipmentModel;
import net.minecraft.client.render.entity.equipment.EquipmentModelLoader; import net.minecraft.client.render.entity.equipment.EquipmentModelLoader;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.EquippableComponent; import net.minecraft.component.type.EquippableComponent;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.item.*; import net.minecraft.item.*;
import net.minecraft.util.Unit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class ArmourFeature< public class ArmourFeature<
@ -23,6 +33,9 @@ public class ArmourFeature<
S extends PonyRenderState, S extends PonyRenderState,
M extends ClientPonyModel<S> M extends ClientPonyModel<S>
> extends AbstractPonyFeature<S, M> { > extends AbstractPonyFeature<S, M> {
private static final Logger LOGGER = LogManager.getLogger("PonifiedEquipmentRenderer");
private static boolean FABRIC_API_FAILURE;
private final PonifiedEquipmentRenderer equipmentRenderer; private final PonifiedEquipmentRenderer equipmentRenderer;
@ -58,17 +71,77 @@ public class ArmourFeature<
ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get(); ArmourRendererPlugin plugin = ArmourRendererPlugin.INSTANCE.get();
for (ItemStack stack : plugin.getArmorStacks(entity, armorSlot, layerType, ArmourRendererPlugin.ArmourType.ARMOUR)) { for (ItemStack stack : plugin.getArmorStacks(entity, armorSlot, layerType, ArmourRendererPlugin.ArmourType.ARMOUR)) {
EquippableComponent equippableComponent = stack.get(DataComponentTypes.EQUIPPABLE); render(armorSlot, layerType, entity, models, stack, matrices, vertices, light, equipmentRenderer);
if (hasModel(equippableComponent, armorSlot)) {
equipmentRenderer.render(armorSlot, layerType, equippableComponent.assetId().orElseThrow(), entity, models, stack, matrices, vertices, light);
}
} }
plugin.onArmourRendered(entity, matrices, vertices, armorSlot, layerType, ArmourRendererPlugin.ArmourType.ARMOUR); plugin.onArmourRendered(entity, matrices, vertices, armorSlot, layerType, ArmourRendererPlugin.ArmourType.ARMOUR);
} }
private static <S extends PonyRenderState, V extends ClientPonyModel<S>> void render(
EquipmentSlot slot,
EquipmentModel.LayerType layerType,
S entity,
Models<V> models,
ItemStack stack,
MatrixStack matrices,
VertexConsumerProvider vertices,
int light, PonifiedEquipmentRenderer equipmentRenderer
) {
if (!FABRIC_API_FAILURE && PonyConfig.getInstance().enableFabricModelsApiSupport.get()) {
try {
if (FabricArmorRendererInvoker.renderArmor(stack, models, matrices, vertices, light, entity, slot, layerType)) {
return;
}
} catch (Throwable t) {
LOGGER.error("Failure calling fabric armor rendering api", t);
FABRIC_API_FAILURE = true;
}
}
EquippableComponent equippableComponent = stack.get(DataComponentTypes.EQUIPPABLE);
if (hasModel(equippableComponent, slot)) {
equipmentRenderer.render(slot, layerType, equippableComponent.assetId().orElseThrow(), entity, models, stack, matrices, vertices, light, null);
}
}
private static boolean hasModel(@Nullable EquippableComponent component, EquipmentSlot slot) { private static boolean hasModel(@Nullable EquippableComponent component, EquipmentSlot slot) {
return component != null && component.assetId().isPresent() && component.slot() == slot; return component != null && component.assetId().isPresent() && component.slot() == slot;
} }
private static final class FabricArmorRendererInvoker {
private static final Map<ArmorRenderer, Unit> FAILING_RENDERERS = new WeakHashMap<>();
@SuppressWarnings({"rawtypes", "unchecked"})
private static <S extends PonyRenderState, V extends ClientPonyModel<S>> boolean renderArmor(
ItemStack stack,
Models<V> models, MatrixStack matrices,
VertexConsumerProvider vertices, int light, S entity,
EquipmentSlot armorSlot, EquipmentModel.LayerType layerType) {
ArmorRenderer renderer = ArmorRendererRegistryImpl.get(stack.getItem());
if (renderer != null && !FAILING_RENDERERS.containsKey(renderer)) {
MatrixStack isolation = MatrixStackUtil.pushIsolation(matrices);
try {
isolation.push();
models.body().transform(entity, getBodyPart(armorSlot), isolation);
renderer.render(isolation, vertices, stack, entity, armorSlot, light, (BipedEntityModel)models.body());
isolation.pop();
} catch (Throwable t) {
LOGGER.error("Exception occured whilst rendering custom armor via fabric api. Renderer {} has been disabled", renderer, t);
FAILING_RENDERERS.put(renderer, Unit.INSTANCE);
} finally {
MatrixStackUtil.popIsolation();
}
return true;
}
return false;
}
private static BodyPart getBodyPart(EquipmentSlot slot) {
return switch (slot) {
case HEAD -> BodyPart.HEAD;
case CHEST, BODY -> BodyPart.BODY;
case LEGS, FEET, MAINHAND, OFFHAND -> BodyPart.LEGS;
};
}
}
} }

View file

@ -0,0 +1,19 @@
package com.minelittlepony.client.util.render;
import net.minecraft.client.util.math.MatrixStack;
public class MatrixStackUtil {
static final MatrixStack ISOLATION_STACK = new MatrixStack();
public static MatrixStack pushIsolation(MatrixStack matrices) {
ISOLATION_STACK.peek().getNormalMatrix().set(matrices.peek().getNormalMatrix());
ISOLATION_STACK.peek().getPositionMatrix().set(matrices.peek().getPositionMatrix());
return ISOLATION_STACK;
}
public static void popIsolation() {
while (!ISOLATION_STACK.isEmpty()) {
ISOLATION_STACK.pop();
}
}
}

View file

@ -14,6 +14,7 @@
"minelp.options.skins.hdskins.open": "Open HD Skins", "minelp.options.skins.hdskins.open": "Open HD Skins",
"minelp.options.skins.hdskins.disabled": "HD Skins is not installed\n\nThe HD Skins mod is required to upload skins from in-game and to use custom skin servers.\n\nIf you cannot use that you will have to go to www.minecraft.net to upload your skin there.", "minelp.options.skins.hdskins.disabled": "HD Skins is not installed\n\nThe HD Skins mod is required to upload skins from in-game and to use custom skin servers.\n\nIf you cannot use that you will have to go to www.minecraft.net to upload your skin there.",
"minelp.options.snuzzles": "Show Snuzzles", "minelp.options.snuzzles": "Show Snuzzles",
"minelp.options.enablefabricmodelsapisupport": "(Experimental) Show Modded Armor",
"minelp.options.fillycam": "Filly Cam", "minelp.options.fillycam": "Filly Cam",
"minelp.options.showscale": "Show-accurate scaling", "minelp.options.showscale": "Show-accurate scaling",
"minelp.options.fpsmagic": "Magic in first-person", "minelp.options.fpsmagic": "Magic in first-person",