Improve modding support for adding custom gear

This commit is contained in:
Sollace 2021-02-05 22:11:19 +02:00
parent eefb58e6b7
commit abfab92d78
19 changed files with 144 additions and 69 deletions

View file

@ -2,7 +2,7 @@ package com.minelittlepony.client.model;
import com.minelittlepony.client.model.armour.PonyArmourModel;
import com.minelittlepony.client.render.EquineRenderManager;
import com.minelittlepony.model.capabilities.fabric.PonyModelPrepareCallback;
import com.minelittlepony.model.fabric.PonyModelPrepareCallback;
import com.minelittlepony.api.pony.meta.Race;
import com.minelittlepony.api.pony.meta.Sizes;
import com.minelittlepony.client.model.armour.ArmourWrapper;

View file

@ -6,7 +6,7 @@ import net.minecraft.entity.LivingEntity;
import net.minecraft.util.Arm;
import net.minecraft.util.Hand;
import com.minelittlepony.model.capabilities.fabric.PonyModelPrepareCallback;
import com.minelittlepony.model.fabric.PonyModelPrepareCallback;
import com.minelittlepony.api.pony.IPony;
import com.minelittlepony.api.pony.IPonyData;
import com.minelittlepony.api.pony.meta.Size;

View file

@ -4,9 +4,9 @@ import net.minecraft.entity.LivingEntity;
import com.minelittlepony.api.pony.IPonyData;
import com.minelittlepony.model.IModel;
import com.minelittlepony.model.IModelWrapper;
import com.minelittlepony.model.armour.IArmour;
import com.minelittlepony.model.armour.IEquestrianArmour;
import com.minelittlepony.model.capabilities.IModelWrapper;
import com.minelittlepony.mson.api.ModelKey;
/**

View file

@ -25,7 +25,7 @@ public abstract class AbstractGear extends Model implements IGear {
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) {
public void render(MatrixStack stack, VertexConsumer vertices, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) {
render(stack, vertices, overlayUv, lightUv, red, green, blue, alpha);
}

View file

@ -11,11 +11,13 @@ import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.common.util.Color;
import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.IModel;
import com.minelittlepony.model.PonyModelConstants;
import com.minelittlepony.model.gear.IRenderContext;
import java.util.Calendar;
import java.util.UUID;
public class ChristmasHat extends AbstractGear {
public class ChristmasHat extends AbstractGear implements PonyModelConstants {
private static boolean dayChecked = false;
private static boolean dayResult = false;
@ -49,12 +51,12 @@ public class ChristmasHat extends AbstractGear {
}
@Override
public void setLivingAnimations(IModel model, Entity entity) {
public void setModelAttributes(IModel model, Entity entity) {
tint = model.getMetadata().getGlowColor();
}
@Override
public void setRotationAndAngles(boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
public void pose(boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
float pi = PI * (float) Math.pow(swing, 16);
float mve = move * 0.6662f;
@ -79,7 +81,7 @@ public class ChristmasHat extends AbstractGear {
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer vertices, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) {
public void render(MatrixStack stack, VertexConsumer vertices, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) {
if (tint != 0) {
red = Color.r(tint);
green = Color.g(tint);

View file

@ -1,26 +0,0 @@
package com.minelittlepony.client.model.gear;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.model.IModel;
import com.minelittlepony.model.gear.IGear;
import javax.annotation.Nullable;
public interface IRenderContext<T extends Entity, M extends IModel> {
IRenderContext<?, ?> NULL = (e, g) -> null;
default boolean shouldRender(M model, T entity, Wearable wearable, IGear gear) {
return gear.canRender(model, entity);
}
@Nullable
default IModel getEntityModel() {
return null;
}
Identifier getDefaultTexture(T entity, Wearable wearable);
}

View file

@ -7,6 +7,7 @@ import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.IModel;
import com.minelittlepony.model.gear.IRenderContext;
import com.minelittlepony.model.gear.IStackable;
public class Muffin extends AbstractGear implements IStackable {

View file

@ -5,6 +5,8 @@ import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.IModel;
import com.minelittlepony.model.IPegasus;
import com.minelittlepony.model.PonyModelConstants;
import com.minelittlepony.model.gear.IRenderContext;
import java.util.UUID;
@ -15,7 +17,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
public class SaddleBags extends AbstractGear {
public class SaddleBags extends AbstractGear implements PonyModelConstants {
public static final Identifier TEXTURE = new Identifier("minelittlepony", "textures/models/saddlebags.png");
@ -37,7 +39,7 @@ public class SaddleBags extends AbstractGear {
}
@Override
public void setLivingAnimations(IModel model, Entity entity) {
public void setModelAttributes(IModel model, Entity entity) {
this.model = model;
hangLow = false;
@ -48,7 +50,7 @@ public class SaddleBags extends AbstractGear {
}
@Override
public void setRotationAndAngles(boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
public void pose(boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
float pi = PI * (float) Math.pow(swing, 16);
float mve = move * 0.6662f;
@ -75,7 +77,7 @@ public class SaddleBags extends AbstractGear {
}
@Override
public void renderPart(MatrixStack stack, VertexConsumer renderContext, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) {
public void render(MatrixStack stack, VertexConsumer renderContext, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId) {
dropAmount = model.getMetadata().getInterpolator(interpolatorId).interpolate("dropAmount", dropAmount, 3);
stack.push();

View file

@ -7,6 +7,7 @@ import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.IModel;
import com.minelittlepony.model.gear.IRenderContext;
import com.minelittlepony.model.gear.IStackable;
public class Stetson extends AbstractGear implements IStackable {

View file

@ -7,6 +7,7 @@ import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.IModel;
import com.minelittlepony.model.gear.IRenderContext;
import com.minelittlepony.model.gear.IStackable;
public class WitchHat extends AbstractGear implements IStackable {

View file

@ -4,9 +4,9 @@ import com.minelittlepony.api.pony.IPony;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.model.ModelWrapper;
import com.minelittlepony.client.model.gear.IRenderContext;
import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.PonyModelConstants;
import com.minelittlepony.model.gear.IRenderContext;
import com.minelittlepony.util.MathUtil;
import net.minecraft.client.render.entity.model.EntityModel;

View file

@ -8,6 +8,7 @@ import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import com.google.common.collect.Streams;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.client.model.IPonyModel;
import com.minelittlepony.client.model.ModelType;
@ -16,21 +17,27 @@ import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.gear.IGear;
import com.minelittlepony.model.gear.IStackable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & IPonyModel<T>> extends AbstractPonyFeature<T, M> {
private final Map<Wearable, IGear> gears;
private static final List<Entry> MOD_GEARS = new ArrayList<>();
public static IGear addModGear(IGear gear) {
MOD_GEARS.add(new Entry(gear, Wearable.NONE));
return gear;
}
private final List<Entry> gears;
public GearFeature(IPonyRenderContext<T, M> renderer) {
super(renderer);
gears = ModelType.getWearables().collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().createModel()
));
gears = Streams.concat(ModelType.getWearables().map(e -> new Entry(e.getValue().createModel(), e.getKey())), MOD_GEARS.stream()).collect(Collectors.toList());
}
@Override
@ -40,21 +47,20 @@ public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & IPon
return;
}
M model = getModelWrapper().getBody();
final M model = getModelWrapper().getBody();
Map<BodyPart, Float> renderStackingOffsets = new HashMap<>();
final Map<BodyPart, Float> renderStackingOffsets = new HashMap<>();
for (Map.Entry<Wearable, IGear> entry : gears.entrySet()) {
Wearable wearable = entry.getKey();
IGear gear = entry.getValue();
for (Entry entry : gears) {
final IGear gear = entry.gear;
if (getContext().shouldRender(model, entity, wearable, gear)) {
if (getContext().shouldRender(model, entity, entry.wearable, gear)) {
stack.push();
model.transform(gear.getGearLocation(), stack);
model.getBodyPart(gear.getGearLocation()).rotate(stack);
BodyPart part = gear.getGearLocation();
model.transform(part, stack);
model.getBodyPart(part).rotate(stack);
if (gear instanceof IStackable) {
BodyPart part = gear.getGearLocation();
renderStackingOffsets.compute(part, (k, v) -> {
float offset = ((IStackable)gear).getStackingOffset();
if (v != null) {
@ -73,12 +79,22 @@ public class GearFeature<T extends LivingEntity, M extends EntityModel<T> & IPon
private void renderGear(M model, T entity, IGear gear, MatrixStack stack, VertexConsumerProvider renderContext, int lightUv, float limbDistance, float limbAngle, float tickDelta) {
gear.setLivingAnimations(model, entity);
gear.setRotationAndAngles(model.getAttributes().isGoingFast, entity.getUuid(), limbDistance, limbAngle, model.getWobbleAmount(), tickDelta);
gear.setModelAttributes(model, entity);
gear.pose(model.getAttributes().isGoingFast, entity.getUuid(), limbDistance, limbAngle, model.getWobbleAmount(), tickDelta);
RenderLayer layer = RenderLayer.getEntityTranslucent(gear.getTexture(entity, getContext()));
VertexConsumer vertexConsumer = renderContext.getBuffer(layer);
gear.renderPart(stack, vertexConsumer, lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1, entity.getUuid());
gear.render(stack, vertexConsumer, lightUv, OverlayTexture.DEFAULT_UV, 1, 1, 1, 1, entity.getUuid());
}
static class Entry {
IGear gear;
Wearable wearable;
Entry(IGear gear, Wearable wearable) {
this.gear = gear;
this.wearable = wearable;
}
}
}

View file

@ -1,4 +1,4 @@
package com.minelittlepony.model.capabilities;
package com.minelittlepony.model;
import com.minelittlepony.api.pony.IPonyData;

View file

@ -1,6 +1,6 @@
package com.minelittlepony.model.armour;
import com.minelittlepony.model.capabilities.IModelWrapper;
import com.minelittlepony.model.IModelWrapper;
public interface IEquestrianArmour<V extends IArmour> extends IModelWrapper {
/**

View file

@ -1,4 +0,0 @@
@ParametersAreNonnullByDefault
package com.minelittlepony.model.capabilities.fabric;
import javax.annotation.ParametersAreNonnullByDefault;

View file

@ -1,4 +1,4 @@
package com.minelittlepony.model.capabilities.fabric;
package com.minelittlepony.model.fabric;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;

View file

@ -1,4 +1,4 @@
@ParametersAreNonnullByDefault
package com.minelittlepony.model.capabilities;
package com.minelittlepony.model.fabric;
import javax.annotation.ParametersAreNonnullByDefault;

View file

@ -1,14 +1,30 @@
package com.minelittlepony.model.gear;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
import com.minelittlepony.client.model.gear.IRenderContext;
import com.minelittlepony.client.render.entity.feature.GearFeature;
import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.IModel;
import com.minelittlepony.model.IPart;
public interface IGear extends IPart {
import java.util.UUID;
/**
* Interface for an accessory on a pony's body.
*/
public interface IGear {
/**
* Registers a custom gear to be used with the mod.
* <p>
* This would be awesome for creating socks.
*/
static IGear addModGear(IGear gear) {
GearFeature.addModGear(gear);
return gear;
}
/**
* Determines if this wearable can and is worn by the selected entity.
@ -27,14 +43,39 @@ public interface IGear extends IPart {
/**
* Gets the texture to use for this wearable.
* Return null to use the same as the primary model.
*
* If you need to use the player's own skin, use {@link IRenderContext#getDefaultTexture(entity, wearable)}
*/
<T extends Entity> Identifier getTexture(T entity, IRenderContext<T, ?> context);
default <T extends Entity> RenderLayer getLayer(T entity, IRenderContext<T, ?> context) {
return RenderLayer.getEntityTranslucent(getTexture(entity, context));
}
/**
* Orients this wearable.
*/
default void setLivingAnimations(IModel model, Entity entity) {
default void setModelAttributes(IModel model, Entity entity) {
}
/**
* Sets the model's various rotation angles.
*
* See {@link AbstractPonyMode.setRotationAndAngle} for an explanation of the various parameters.
*/
default void pose(boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) {
}
/**
* Renders this model component.
*/
void render(MatrixStack stack, VertexConsumer vertices, int overlayUv, int lightUv, float red, float green, float blue, float alpha, UUID interpolatorId);
/**
* Sets whether this part should be rendered.
*/
default void setVisible(boolean visible) {
}
}

View file

@ -0,0 +1,41 @@
package com.minelittlepony.model.gear;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
import com.minelittlepony.api.pony.meta.Wearable;
import com.minelittlepony.model.IModel;
import javax.annotation.Nullable;
/**
* A render context for instance of IGear.
*
* @param <T> The type of entity being rendered.
* @param <M> The type of the entity's primary model.
*/
public interface IRenderContext<T extends Entity, M extends IModel> {
/**
* The empty context.
*/
IRenderContext<?, ?> NULL = (e, g) -> null;
/**
* Checks whether the given wearable and gear are able to render for this specific entity and its renderer.
*/
default boolean shouldRender(M model, T entity, Wearable wearable, IGear gear) {
return gear.canRender(model, entity);
}
@Nullable
default M getEntityModel() {
return null;
}
/**
* Gets the default texture to use for this entity and wearable.
*
* May be the entity's own texture or a specific texture allocated for that wearable.
*/
Identifier getDefaultTexture(T entity, Wearable wearable);
}