mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 07:17:58 +01:00
Entities enticed by want it need it now have hearts over their eyes
This commit is contained in:
parent
159a870599
commit
63d6e96da4
11 changed files with 258 additions and 7 deletions
|
@ -0,0 +1,82 @@
|
|||
package com.minelittlepony.unicopia.client.render;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import net.minecraft.client.model.ModelPart;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
public class ModelPartHooks {
|
||||
private static final float PIXEL_SCALE = 0.0625F; // 1/16;
|
||||
private static Stack<Set<EnqueudHeadRender>> renderCalls = new Stack<>();
|
||||
|
||||
public static void startCollecting() {
|
||||
renderCalls.push(new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
public static Set<EnqueudHeadRender> stopCollecting() {
|
||||
return renderCalls.isEmpty() ? Set.of() : renderCalls.pop();
|
||||
}
|
||||
|
||||
public static void onHeadRendered(ModelPart part, MatrixStack matrices) {
|
||||
if (part.hidden || !part.visible || renderCalls.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var head = renderCalls.peek();
|
||||
if (head.size() > 5) {
|
||||
renderCalls.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
final var bestCandidate = new EnqueudHeadRender();
|
||||
|
||||
matrices.push();
|
||||
part.forEachCuboid(matrices, (entry, name, index, cube) -> {
|
||||
float x = cube.maxX - cube.minX;
|
||||
float y = cube.maxY - cube.minY;
|
||||
float z = cube.maxZ - cube.minZ;
|
||||
|
||||
float volume = div(Math.abs(x * y * z), Math.abs(x + y + z)) * 3F;
|
||||
|
||||
if (volume > 0 && volume > bestCandidate.volume) {
|
||||
bestCandidate.cube = cube;
|
||||
bestCandidate.transformation = entry;
|
||||
bestCandidate.volume = volume;
|
||||
bestCandidate.maxSideLength = Math.max(Math.max(x, z), y);
|
||||
}
|
||||
});
|
||||
matrices.pop();
|
||||
|
||||
if (bestCandidate.transformation != null) {
|
||||
head.add(bestCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
static float div(float a, float b) {
|
||||
return b == 0 ? 0 : a / b;
|
||||
}
|
||||
|
||||
public static final class EnqueudHeadRender {
|
||||
private ModelPart.Cuboid cube;
|
||||
private MatrixStack.Entry transformation;
|
||||
private float volume;
|
||||
private float maxSideLength;
|
||||
|
||||
public void transform(MatrixStack matrices, float cubeSize) {
|
||||
matrices.peek().getNormalMatrix().set(transformation.getNormalMatrix());
|
||||
matrices.peek().getPositionMatrix().set(transformation.getPositionMatrix());
|
||||
|
||||
float x = MathHelper.lerp(0.5F, cube.minX, cube.maxX);
|
||||
float y = MathHelper.lerp(0.5F, cube.minY, cube.maxY);
|
||||
float z = MathHelper.lerp(0.5F, cube.minZ, cube.maxZ);
|
||||
float scale = (maxSideLength / cubeSize) * PIXEL_SCALE;
|
||||
|
||||
matrices.translate(x * PIXEL_SCALE, y * PIXEL_SCALE, z * PIXEL_SCALE);
|
||||
matrices.scale(scale, scale, scale);
|
||||
//matrices.peek().getPositionMatrix().scaleAround(scale, x * PIXEL_SCALE, y * PIXEL_SCALE, z * PIXEL_SCALE);
|
||||
//matrices.translate(cube.minX * PIXEL_SCALE, cube.minY * PIXEL_SCALE, cube.minZ * PIXEL_SCALE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.minelittlepony.unicopia.client.render;
|
||||
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate;
|
||||
import com.minelittlepony.unicopia.entity.Creature;
|
||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.model.Dilation;
|
||||
import net.minecraft.client.model.ModelData;
|
||||
import net.minecraft.client.model.ModelPart;
|
||||
import net.minecraft.client.model.ModelPartBuilder;
|
||||
import net.minecraft.client.model.ModelTransform;
|
||||
import net.minecraft.client.model.TexturedModelData;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.RotationAxis;
|
||||
|
||||
public class SmittenEyesRenderer {
|
||||
public static final SmittenEyesRenderer INSTANCE = new SmittenEyesRenderer();
|
||||
|
||||
private static final Identifier TEXTURE = Unicopia.id("textures/entity/smitten_eyes.png");
|
||||
|
||||
private final MinecraftClient client = MinecraftClient.getInstance();
|
||||
private final ModelPart model;
|
||||
|
||||
SmittenEyesRenderer() {
|
||||
ModelData data = new ModelData();
|
||||
data.getRoot().addChild("hearts", ModelPartBuilder.create()
|
||||
.uv(0, 0)
|
||||
.cuboid(-4, -4, -4, 8.0f, 8.0f, 8.0f, Dilation.NONE), ModelTransform.NONE);
|
||||
model = TexturedModelData.of(data, 32, 32).createModel();
|
||||
}
|
||||
|
||||
public void render(Creature pony, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
|
||||
VertexConsumer buffer = vertices.getBuffer(RenderLayer.getEntityCutout(TEXTURE));
|
||||
|
||||
ModelPartHooks.stopCollecting().forEach(head -> {
|
||||
matrices.push();
|
||||
head.transform(matrices, 0.95F);
|
||||
if (MineLPDelegate.getInstance().getRace(pony.asEntity()).isEquine()) {
|
||||
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-90), 0, 1.2F, 0);
|
||||
}
|
||||
float scale = 1F + (1.3F + MathHelper.sin(pony.asEntity().age / 3F) * 0.06F);
|
||||
matrices.scale(scale, scale, scale);
|
||||
matrices.translate(0, 0.05F, 0);
|
||||
model.render(matrices, buffer, light, overlay, 1, 1, 1, 1);
|
||||
|
||||
if (client.getEntityRenderDispatcher().shouldRenderHitboxes()) {
|
||||
VertexConsumer lines = vertices.getBuffer(RenderLayer.getLines());
|
||||
WorldRenderer.drawBox(matrices, lines, new Box(-0.25, 0, -0.25, 0.25, 0.25, 0.25), 1, 1, 0, 1);
|
||||
WorldRenderer.drawBox(matrices, lines, new Box(-0.25, -0.25, -0.25, 0.25, 0, 0.25), 1, 0, 1, 1);
|
||||
}
|
||||
|
||||
matrices.pop();
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isSmitten(Creature pony) {
|
||||
return pony.isSmitten() || WantItNeedItEnchantment.getLevel(pony.asEntity()) > 0;
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ import net.minecraft.block.BlockState;
|
|||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.*;
|
||||
import net.minecraft.client.render.VertexConsumerProvider.Immediate;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||
import net.minecraft.client.render.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.render.entity.LivingEntityRenderer;
|
||||
|
@ -146,6 +147,8 @@ public class WorldRenderDelegate {
|
|||
|
||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(diveAngle));
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw));
|
||||
} else if (pony instanceof Creature creature && SmittenEyesRenderer.INSTANCE.isSmitten(creature)) {
|
||||
ModelPartHooks.startCollecting();
|
||||
}
|
||||
|
||||
matrices.translate(-x, -y - owner.getHeight() / 2, -z);
|
||||
|
@ -178,7 +181,7 @@ public class WorldRenderDelegate {
|
|||
PehkUtil.clearScale(ee);
|
||||
});
|
||||
|
||||
afterEntityRender(pony, matrices);
|
||||
afterEntityRender(pony, matrices, light);
|
||||
PehkUtil.clearScale(e);
|
||||
return true;
|
||||
}
|
||||
|
@ -189,11 +192,16 @@ public class WorldRenderDelegate {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void afterEntityRender(Equine<?> pony, MatrixStack matrices) {
|
||||
public void afterEntityRender(Equine<?> pony, MatrixStack matrices, int light) {
|
||||
if (recurseFrosting) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pony instanceof Creature creature && SmittenEyesRenderer.INSTANCE.isSmitten(creature)) {
|
||||
Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
|
||||
SmittenEyesRenderer.INSTANCE.render(creature, matrices, immediate, light, 0);
|
||||
}
|
||||
|
||||
if (pony instanceof ItemImpl || pony instanceof Living) {
|
||||
matrices.pop();
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
public static final TrackedData<Float> GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||
private static final TrackedData<Integer> EATING = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
private static final TrackedData<Boolean> DISCORDED = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
private static final TrackedData<Boolean> SMITTEN = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
|
||||
public static void boostrap() {}
|
||||
|
||||
|
@ -56,6 +57,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
private EatMuffinGoal eatMuffinGoal;
|
||||
|
||||
private boolean discordedChanged = true;
|
||||
private int smittenTicks;
|
||||
|
||||
private final Predicate<LivingEntity> targetPredicate = TargetSelecter.<LivingEntity>notOwnerOrFriend(() -> getOriginatingCaster().getAffinity(), this).and(e -> {
|
||||
return Equine.of(e)
|
||||
|
@ -70,6 +72,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
entity.getDataTracker().startTracking(MASTER, owner.toNBT());
|
||||
entity.getDataTracker().startTracking(EATING, 0);
|
||||
entity.getDataTracker().startTracking(DISCORDED, false);
|
||||
entity.getDataTracker().startTracking(SMITTEN, false);
|
||||
|
||||
addTicker(physics);
|
||||
addTicker(this::updateConsumption);
|
||||
|
@ -92,6 +95,15 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
return entity.getDataTracker().get(DISCORDED);
|
||||
}
|
||||
|
||||
public boolean isSmitten() {
|
||||
return entity.getDataTracker().get(SMITTEN);
|
||||
}
|
||||
|
||||
public void setSmitten(boolean smitten) {
|
||||
smittenTicks = smitten ? 20 : 0;
|
||||
entity.getDataTracker().set(SMITTEN, smitten);
|
||||
}
|
||||
|
||||
public void setDiscorded(boolean discorded) {
|
||||
entity.getDataTracker().set(DISCORDED, discorded);
|
||||
discordedChanged = true;
|
||||
|
@ -131,7 +143,7 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
DynamicTargetGoal targetter = new DynamicTargetGoal((MobEntity)entity);
|
||||
targets.add(1, targetter);
|
||||
if (!Unicopia.getConfig().wantItNeedItEntityExcludelist.get().contains(EntityType.getId(entity.getType()).toString())) {
|
||||
goals.add(1, new WantItTakeItGoal((MobEntity)entity, targetter));
|
||||
goals.add(1, new WantItTakeItGoal(this, targetter));
|
||||
}
|
||||
if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) {
|
||||
goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter));
|
||||
|
@ -199,6 +211,12 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
|
|||
initDiscordedAi();
|
||||
}
|
||||
|
||||
if (!isClient() && smittenTicks > 0) {
|
||||
if (--smittenTicks <= 0) {
|
||||
setSmitten(false);
|
||||
}
|
||||
}
|
||||
|
||||
return super.beforeUpdate();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,10 @@ import java.util.List;
|
|||
|
||||
import com.minelittlepony.unicopia.*;
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
|
@ -56,6 +60,16 @@ public class ItemImpl implements Equine<ItemEntity> {
|
|||
setSpecies(Race.HUMAN);
|
||||
setSpecies(race);
|
||||
}
|
||||
|
||||
if (WantItNeedItEnchantment.getLevel(entity) > 0) {
|
||||
var random = entity.getWorld().random;
|
||||
|
||||
if (random.nextInt(15) == 0) {
|
||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, entity.getPos().add(
|
||||
VecHelper.sphere(random).get().add(0, 1, 0)
|
||||
), 0.2F), entity, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack stack = entity.getStack();
|
||||
|
|
|
@ -2,11 +2,14 @@ package com.minelittlepony.unicopia.entity.ai;
|
|||
|
||||
import com.minelittlepony.unicopia.AwaitTickQueue;
|
||||
import com.minelittlepony.unicopia.EquinePredicates;
|
||||
import com.minelittlepony.unicopia.entity.Creature;
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
import com.minelittlepony.unicopia.item.enchantment.WantItNeedItEnchantment;
|
||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
|
@ -26,8 +29,11 @@ public class WantItTakeItGoal extends BreakHeartGoal {
|
|||
|
||||
protected int cooldown;
|
||||
|
||||
public WantItTakeItGoal(MobEntity mob, DynamicTargetGoal targetter) {
|
||||
super(mob, targetter);
|
||||
private final Creature creature;
|
||||
|
||||
public WantItTakeItGoal(Creature creature, DynamicTargetGoal targetter) {
|
||||
super((MobEntity)creature.asEntity(), targetter);
|
||||
this.creature = creature;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,7 +47,7 @@ public class WantItTakeItGoal extends BreakHeartGoal {
|
|||
|
||||
@Override
|
||||
protected void attackTarget(Entity target, double reach, double distance) {
|
||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, mob, 0.2F), mob, 1);
|
||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, mob.getPos().add(VecHelper.sphere(mob.getWorld().random).get()), 0.2F), mob, 1);
|
||||
|
||||
double speed = 0.8D;
|
||||
|
||||
|
@ -59,6 +65,7 @@ public class WantItTakeItGoal extends BreakHeartGoal {
|
|||
mob.getNavigation().startMovingTo(target, speed);
|
||||
|
||||
cooldown = Math.max(cooldown - 1, 0);
|
||||
creature.setSmitten(true);
|
||||
|
||||
if (distance <= reach) {
|
||||
if (target instanceof LivingEntity) {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package com.minelittlepony.unicopia.entity.duck;
|
||||
|
||||
public interface Hookable {
|
||||
void enableHooks();
|
||||
}
|
|
@ -27,6 +27,6 @@ abstract class MixinEntityRenderDispatcher {
|
|||
|
||||
@Inject(method = RENDER, at = @At("RETURN"))
|
||||
private <E extends Entity> void afterRender(E entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo info) {
|
||||
Equine.of(entity).ifPresent(eq -> WorldRenderDelegate.INSTANCE.afterEntityRender(eq, matrices));
|
||||
Equine.of(entity).ifPresent(eq -> WorldRenderDelegate.INSTANCE.afterEntityRender(eq, matrices, light));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package com.minelittlepony.unicopia.mixin.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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;
|
||||
|
||||
import com.minelittlepony.unicopia.client.render.ModelPartHooks;
|
||||
import com.minelittlepony.unicopia.entity.duck.Hookable;
|
||||
|
||||
import net.minecraft.client.model.ModelPart;
|
||||
import net.minecraft.client.model.ModelPart.Cuboid;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.entity.model.EntityModelPartNames;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
@Mixin(ModelPart.class)
|
||||
abstract class MixinModelPart implements Hookable {
|
||||
@Unique
|
||||
private boolean isHeadPart;
|
||||
|
||||
@Shadow
|
||||
private boolean visible;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void onModelPart(List<Cuboid> cuboids, Map<String, ModelPart> children, CallbackInfo info) {
|
||||
if (((Object)children.getOrDefault(EntityModelPartNames.HEAD, null)) instanceof Hookable hook) {
|
||||
hook.enableHooks();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableHooks() {
|
||||
isHeadPart = true;
|
||||
}
|
||||
|
||||
@Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;IIFFFF)V", at = @At("RETURN"))
|
||||
public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha, CallbackInfo info) {
|
||||
if (visible && isHeadPart) {
|
||||
ModelPartHooks.onHeadRendered((ModelPart)(Object)this, matrices);
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
|
@ -65,6 +65,7 @@
|
|||
"client.MixinItemModels",
|
||||
"client.MixinKeyboardInput",
|
||||
"client.MixinLivingEntityRenderer",
|
||||
"client.MixinModelPart",
|
||||
"client.MixinMouse",
|
||||
"client.MixinPlayerEntityRenderer",
|
||||
"client.MixinTooltipComponent",
|
||||
|
|
Loading…
Reference in a new issue