mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-12-17 23:48:00 +01:00
More work on hot air balloons
This commit is contained in:
parent
2e472a7982
commit
5448db4bdd
8 changed files with 274 additions and 81 deletions
|
@ -6,6 +6,7 @@ import net.minecraft.client.model.*;
|
||||||
import net.minecraft.client.render.VertexConsumer;
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
import net.minecraft.client.render.entity.model.EntityModel;
|
import net.minecraft.client.render.entity.model.EntityModel;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
||||||
|
|
||||||
|
@ -13,13 +14,11 @@ public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
||||||
|
|
||||||
private final ModelPart burner;
|
private final ModelPart burner;
|
||||||
private final ModelPart balloon;
|
private final ModelPart balloon;
|
||||||
private final ModelPart basket;
|
|
||||||
|
|
||||||
public AirBalloonEntityModel(ModelPart root) {
|
public AirBalloonEntityModel(ModelPart root) {
|
||||||
this.root = root;
|
this.root = root;
|
||||||
burner = root.getChild("burner");
|
burner = root.getChild("burner");
|
||||||
balloon = root.getChild("balloon");
|
balloon = root.getChild("balloon");
|
||||||
basket = root.getChild("basket");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TexturedModelData getTexturedModelData() {
|
public static TexturedModelData getTexturedModelData() {
|
||||||
|
@ -43,16 +42,23 @@ public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
||||||
.uv(64, 68).cuboid(15, -12, -16, 2, 11, 30, Dilation.NONE)
|
.uv(64, 68).cuboid(15, -12, -16, 2, 11, 30, Dilation.NONE)
|
||||||
.uv(80, 38).cuboid(-16, -12, -17, 32, 11, 2, Dilation.NONE)
|
.uv(80, 38).cuboid(-16, -12, -17, 32, 11, 2, Dilation.NONE)
|
||||||
.uv(0, 32).cuboid(8, -12, 13, 8, 11, 2, Dilation.NONE)
|
.uv(0, 32).cuboid(8, -12, 13, 8, 11, 2, Dilation.NONE)
|
||||||
.uv(0, 6).cuboid(-16, -12, 13, 8, 11, 2, Dilation.NONE), ModelTransform.pivot(0, 0, 0));
|
.uv(0, 6).cuboid(-16, -12, 13, 8, 11, 2, Dilation.NONE), ModelTransform.NONE);
|
||||||
basket.addChild("rim", ModelPartBuilder.create().uv(40, 34).cuboid(-18, -13, -17, 4, 2, 32, Dilation.NONE)
|
basket.addChild("rim", ModelPartBuilder.create().uv(40, 34).cuboid(-18, -13, -17, 4, 2, 32, Dilation.NONE)
|
||||||
.uv(0, 32).cuboid(14, -13, -17, 4, 2, 32, Dilation.NONE)
|
.uv(0, 32).cuboid(14, -13, -17, 4, 2, 32, Dilation.NONE)
|
||||||
.uv(80, 32).cuboid(-17, -13, -18, 34, 2, 4, Dilation.NONE)
|
.uv(80, 32).cuboid(-17, -13, -18, 34, 2, 4, Dilation.NONE)
|
||||||
.uv(0, 19).cuboid(7, -13, 12, 10, 2, 4, Dilation.NONE)
|
.uv(0, 19).cuboid(7, -13, 12, 10, 2, 4, Dilation.NONE)
|
||||||
.uv(0, 0).cuboid(-17, -13, 12, 10, 2, 4, Dilation.NONE), ModelTransform.pivot(0, 0, 0));
|
.uv(0, 0).cuboid(-17, -13, 12, 10, 2, 4, Dilation.NONE), ModelTransform.NONE);
|
||||||
return TexturedModelData.of(modelData, 512, 512);
|
return TexturedModelData.of(modelData, 512, 512);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void setAngles(AirBalloonEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
|
public void setAngles(AirBalloonEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
|
||||||
|
root.yaw = entity.bodyYaw;
|
||||||
|
burner.visible = entity.hasBurner();
|
||||||
|
balloon.visible = entity.hasBalloon();
|
||||||
|
|
||||||
|
float xSpeed = (float)(entity.getX() - entity.prevX);
|
||||||
|
|
||||||
|
root.pitch = MathHelper.sin(-xSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,12 +2,12 @@ package com.minelittlepony.unicopia.client.render.entity;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
import com.minelittlepony.unicopia.entity.AirBalloonEntity;
|
import com.minelittlepony.unicopia.entity.AirBalloonEntity;
|
||||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
|
||||||
import net.minecraft.client.render.entity.LivingEntityRenderer;
|
import net.minecraft.client.render.entity.*;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
public class AirBalloonEntityRenderer extends LivingEntityRenderer<AirBalloonEntity, AirBalloonEntityModel> {
|
public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity, AirBalloonEntityModel> {
|
||||||
private static final Identifier TEXTURE = Unicopia.id("textures/entity/spellbook/normal.png");
|
private static final Identifier TEXTURE = Unicopia.id("textures/entity/air_balloon.png");
|
||||||
|
|
||||||
public AirBalloonEntityRenderer(EntityRendererFactory.Context context) {
|
public AirBalloonEntityRenderer(EntityRendererFactory.Context context) {
|
||||||
super(context, new AirBalloonEntityModel(AirBalloonEntityModel.getTexturedModelData().createModel()), 0);
|
super(context, new AirBalloonEntityModel(AirBalloonEntityModel.getTexturedModelData().createModel()), 0);
|
||||||
|
|
|
@ -1,13 +1,25 @@
|
||||||
package com.minelittlepony.unicopia.entity;
|
package com.minelittlepony.unicopia.entity;
|
||||||
|
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.entity.*;
|
import net.minecraft.entity.*;
|
||||||
|
import net.minecraft.entity.data.*;
|
||||||
import net.minecraft.entity.mob.FlyingEntity;
|
import net.minecraft.entity.mob.FlyingEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.util.math.Box;
|
import net.minecraft.util.math.*;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class AirBalloonEntity extends FlyingEntity {
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.entity.collision.EntityCollisions;
|
||||||
|
|
||||||
|
public class AirBalloonEntity extends FlyingEntity implements EntityCollisions.ComplexCollidable {
|
||||||
|
private static final byte HAS_BALLOON = 1;
|
||||||
|
private static final byte HAS_BURNER = 2;
|
||||||
|
private static final byte BURNER_ACTIVE = 4;
|
||||||
|
private static final TrackedData<Integer> FLAGS = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||||
|
|
||||||
public AirBalloonEntity(EntityType<? extends AirBalloonEntity> type, World world) {
|
public AirBalloonEntity(EntityType<? extends AirBalloonEntity> type, World world) {
|
||||||
super(type, world);
|
super(type, world);
|
||||||
|
@ -16,30 +28,103 @@ public class AirBalloonEntity extends FlyingEntity {
|
||||||
@Override
|
@Override
|
||||||
protected void initDataTracker() {
|
protected void initDataTracker() {
|
||||||
super.initDataTracker();
|
super.initDataTracker();
|
||||||
|
dataTracker.startTracking(FLAGS, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasBalloon() {
|
||||||
|
return getFlag(HAS_BALLOON);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasBalloon(boolean hasBalloon) {
|
||||||
|
setFlag(HAS_BALLOON, hasBalloon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasBurner() {
|
||||||
|
return getFlag((byte)(HAS_BURNER | HAS_BALLOON));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasBurner(boolean hasBurner) {
|
||||||
|
setFlag(HAS_BURNER, hasBurner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBurnerActive() {
|
||||||
|
return getFlag((byte)(HAS_BURNER | BURNER_ACTIVE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBurnerActive(boolean burnerActive) {
|
||||||
|
setFlag(BURNER_ACTIVE, burnerActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getFlag(byte flag) {
|
||||||
|
return (dataTracker.get(FLAGS).intValue() & flag) == flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFlag(byte flag, boolean val) {
|
||||||
|
int v = dataTracker.get(FLAGS);
|
||||||
|
dataTracker.set(FLAGS, val ? (v | flag) : (v & ~flag));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAirworthy() {
|
||||||
|
return hasBalloon() && (!onGround || isBurnerActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
this.setHasBalloon(true);
|
||||||
|
this.setHasBurner(true);
|
||||||
|
this.setBurnerActive(false);
|
||||||
|
|
||||||
if (!world.isClient) {
|
setAir(getMaxAir());
|
||||||
|
|
||||||
float xSpeed = 0;//-0.015F * (this.age % 1000 < 500 ? -1 : 1);
|
if (isAirworthy()) {
|
||||||
|
setVelocity(getVelocity()
|
||||||
addVelocity(xSpeed, 0, 0);
|
.add(getWind(world, getBlockPos()))
|
||||||
|
.normalize()
|
||||||
|
.multiply(0.2)
|
||||||
|
.add(0, isBurnerActive() ? 0.09F : isTouchingWater() ? 0.02F : -0.06F, 0));
|
||||||
|
} else {
|
||||||
|
addVelocity(0, isTouchingWater() ? 0.02F : -0.02F, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isLeashed()) {
|
||||||
|
Vec3d leashPost = getHoldingEntity().getPos();
|
||||||
|
Vec3d pos = getPos();
|
||||||
|
|
||||||
|
if (leashPost.distanceTo(pos) >= 5) {
|
||||||
|
Vec3d newVel = leashPost.subtract(pos).multiply(0.01);
|
||||||
|
setVelocity(newVel.lengthSquared() < 0.03 ? Vec3d.ZERO : newVel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (age % 20 < 10) {
|
||||||
|
if (getVelocity().y < 0.1) {
|
||||||
|
addVelocity(0, 0.01, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (getVelocity().y > -0.1) {
|
||||||
|
addVelocity(0, -0.01, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//setVelocity(Vec3d.ZERO);
|
||||||
|
float weight = 0;
|
||||||
|
|
||||||
|
if (getVelocity().length() > 0) {
|
||||||
|
Box box = getBoundingBox();
|
||||||
|
for (var e : this.world.getOtherEntities(this, box.expand(1, 1.0E-7, 1))) {
|
||||||
|
Vec3d vel = e.getVelocity();
|
||||||
|
|
||||||
|
if (getVelocity().y > 0 && box.maxY > e.getBoundingBox().minY) {
|
||||||
|
e.setPosition(e.getX(), box.maxY + 0.1, e.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
for (var e : this.world.getOtherEntities(this, getBoundingBox().expand(0.2, 1.0E-7, 0.2))) {
|
|
||||||
if (!(e instanceof PlayerEntity)) {
|
if (!(e instanceof PlayerEntity)) {
|
||||||
e.setVelocity(e.getVelocity().multiply(0.3).add(getVelocity().multiply(0.84)));
|
e.setVelocity(vel.multiply(0.3).add(getVelocity().multiply(0.786)));
|
||||||
|
|
||||||
double diff = (getBoundingBox().maxY + getVelocity().y) - e.getBoundingBox().minY;
|
|
||||||
|
|
||||||
if (diff > 0) {
|
|
||||||
e.addVelocity(0, diff, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.setOnGround(true);
|
||||||
|
|
||||||
|
if (horizontalSpeed != 0) {
|
||||||
e.distanceTraveled = 0;
|
e.distanceTraveled = 0;
|
||||||
e.horizontalSpeed = 0;
|
e.horizontalSpeed = 0;
|
||||||
if (e instanceof LivingEntity l) {
|
if (e instanceof LivingEntity l) {
|
||||||
|
@ -48,13 +133,41 @@ public class AirBalloonEntity extends FlyingEntity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.tick();
|
weight++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Box balloonTopBox = getBoundingBox().offset(0.125, 11, 0).expand(2.25, 0, 2);
|
||||||
|
|
||||||
|
for (var e : this.world.getOtherEntities(this, balloonTopBox.expand(1.0E-7))) {
|
||||||
|
Vec3d vel = e.getVelocity();
|
||||||
|
|
||||||
|
double yVel = vel.y + Math.max(balloonTopBox.maxY - e.getBoundingBox().minY, 0);
|
||||||
|
yVel /= 8;
|
||||||
|
yVel += 0.3;
|
||||||
|
|
||||||
|
e.setVelocity(vel.getX(), yVel, vel.getZ());
|
||||||
|
e.setVelocity(e.getVelocity().multiply(0.3).add(getVelocity().multiply(0.786)));
|
||||||
|
e.setOnGround(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getVelocity().y > -0.6 && !isTouchingWater()) {
|
||||||
|
if (isBurnerActive()) {
|
||||||
|
weight -= 3;
|
||||||
|
}
|
||||||
|
addVelocity(0, MathHelper.clamp(-weight / 10F, -1, isLeashed() ? 0.2F : 1), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlayerCollision(PlayerEntity player) {
|
public void onPlayerCollision(PlayerEntity player) {
|
||||||
player.setVelocity(player.getVelocity().multiply(0.9).add(getVelocity().multiply(0.56)));
|
if (getVelocity().lengthSquared() > 0) {
|
||||||
|
// player.setVelocity(getVelocity().multiply(1.3));
|
||||||
|
player.setVelocity(player.getVelocity().multiply(0.3).add(getVelocity().multiply(
|
||||||
|
getVelocity().y < 0 ? 0.828 : 0.728
|
||||||
|
)));
|
||||||
|
|
||||||
double diff = (getBoundingBox().maxY + getVelocity().y) - player.getBoundingBox().minY;
|
double diff = (getBoundingBox().maxY + getVelocity().y) - player.getBoundingBox().minY;
|
||||||
|
|
||||||
|
@ -62,6 +175,7 @@ public class AirBalloonEntity extends FlyingEntity {
|
||||||
player.addVelocity(0, diff, 0);
|
player.addVelocity(0, diff, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCollidable() {
|
public boolean isCollidable() {
|
||||||
|
@ -87,14 +201,53 @@ public class AirBalloonEntity extends FlyingEntity {
|
||||||
return getBoundingBox().expand(30, 100, 30);
|
return getBoundingBox().expand(30, 100, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output) {
|
||||||
|
|
||||||
|
Box box = getBoundingBox().expand(0.3, 0, 0.3);
|
||||||
|
|
||||||
|
double wallheight = box.maxY + 1;
|
||||||
|
double wallThickness = 0.7;
|
||||||
|
|
||||||
|
output.accept(VoxelShapes.cuboid(new Box(box.minX, box.minY, box.minZ, box.minX + wallThickness + 0.2, wallheight, box.minZ + wallThickness)));
|
||||||
|
output.accept(VoxelShapes.cuboid(new Box(box.maxX - wallThickness - 0.2, box.minY, box.minZ, box.maxX, wallheight, box.minZ + wallThickness)));
|
||||||
|
output.accept(VoxelShapes.cuboid(new Box(box.minX, box.minY, box.maxZ - wallThickness, box.maxX, wallheight, box.maxZ)));
|
||||||
|
|
||||||
|
output.accept(VoxelShapes.cuboid(new Box(box.minX, box.minY, box.minZ, box.minX + wallThickness, wallheight, box.maxZ)));
|
||||||
|
output.accept(VoxelShapes.cuboid(new Box(box.maxX - wallThickness, box.minY, box.minZ, box.maxX, wallheight, box.maxZ)));
|
||||||
|
|
||||||
|
// top of balloon
|
||||||
|
if (hasBalloon()) {
|
||||||
|
output.accept(VoxelShapes.cuboid(getBoundingBox().offset(0.125, 11, 0).expand(2.25, 0, 2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readCustomDataFromNbt(NbtCompound compound) {
|
public void readCustomDataFromNbt(NbtCompound compound) {
|
||||||
super.readCustomDataFromNbt(compound);
|
super.readCustomDataFromNbt(compound);
|
||||||
|
setHasBalloon(compound.getBoolean("hasBalloon"));
|
||||||
|
setHasBurner(compound.getBoolean("hasBurner"));
|
||||||
|
setBurnerActive(compound.getBoolean("burnerActive"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeCustomDataToNbt(NbtCompound compound) {
|
public void writeCustomDataToNbt(NbtCompound compound) {
|
||||||
super.writeCustomDataToNbt(compound);
|
super.writeCustomDataToNbt(compound);
|
||||||
|
compound.putBoolean("hasBalloon", hasBalloon());
|
||||||
|
compound.putBoolean("hasBurner", hasBurner());
|
||||||
|
compound.putBoolean("burnerActive", isBurnerActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Vec3d getWind(World world, BlockPos pos) {
|
||||||
|
return Vec3d.ofCenter(pos).normalize().multiply(1, 0, 1).multiply(0.2);//.multiply((world.getRandom().nextFloat() - 0.5) * 0.2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ public interface UEntities {
|
||||||
.dimensions(EntityDimensions.fixed(0.9F, 0.5F)));
|
.dimensions(EntityDimensions.fixed(0.9F, 0.5F)));
|
||||||
EntityType<AirBalloonEntity> AIR_BALLOON = register("air_balloon", FabricEntityTypeBuilder.create(SpawnGroup.MISC, AirBalloonEntity::new)
|
EntityType<AirBalloonEntity> AIR_BALLOON = register("air_balloon", FabricEntityTypeBuilder.create(SpawnGroup.MISC, AirBalloonEntity::new)
|
||||||
.trackRangeBlocks(1000)
|
.trackRangeBlocks(1000)
|
||||||
.dimensions(EntityDimensions.fixed(3, 0.1F)));
|
.dimensions(EntityDimensions.fixed(2.5F, 0.1F)));
|
||||||
|
|
||||||
static <T extends Entity> EntityType<T> register(String name, FabricEntityTypeBuilder<T> builder) {
|
static <T extends Entity> EntityType<T> register(String name, FabricEntityTypeBuilder<T> builder) {
|
||||||
EntityType<T> type = builder.build();
|
EntityType<T> type = builder.build();
|
||||||
|
|
|
@ -14,8 +14,8 @@ import com.minelittlepony.unicopia.FlightType;
|
||||||
import com.minelittlepony.unicopia.InteractionManager;
|
import com.minelittlepony.unicopia.InteractionManager;
|
||||||
import com.minelittlepony.unicopia.Owned;
|
import com.minelittlepony.unicopia.Owned;
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
|
||||||
import com.minelittlepony.unicopia.entity.UEntityAttributes;
|
import com.minelittlepony.unicopia.entity.UEntityAttributes;
|
||||||
|
import com.minelittlepony.unicopia.entity.collision.EntityCollisions;
|
||||||
import com.minelittlepony.unicopia.entity.player.PlayerDimensions;
|
import com.minelittlepony.unicopia.entity.player.PlayerDimensions;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
import com.minelittlepony.unicopia.projectile.ProjectileUtil;
|
import com.minelittlepony.unicopia.projectile.ProjectileUtil;
|
||||||
|
@ -42,14 +42,9 @@ import net.minecraft.entity.mob.VexEntity;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.projectile.ShulkerBulletEntity;
|
import net.minecraft.entity.projectile.ShulkerBulletEntity;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.util.function.BooleanBiFunction;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Box;
|
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
|
||||||
import net.minecraft.world.WorldAccess;
|
|
||||||
|
|
||||||
public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider {
|
public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provider, FlightType.Provider, EntityCollisions.ComplexCollidable {
|
||||||
private static final Optional<Float> BLOCK_HEIGHT = Optional.of(0.5F);
|
private static final Optional<Float> BLOCK_HEIGHT = Optional.of(0.5F);
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@ -358,43 +353,10 @@ public class EntityAppearance implements NbtSerialisable, PlayerDimensions.Provi
|
||||||
return entityNbt;
|
return entityNbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output) {
|
@Override
|
||||||
getCollissionShapes(getAppearance(), context, output);
|
public void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output) {
|
||||||
getAttachments().forEach(e -> getCollissionShapes(e, context, output));
|
EntityCollisions.getCollissionShapes(getAppearance(), context, output);
|
||||||
|
getAttachments().forEach(e -> EntityCollisions.getCollissionShapes(e, context, output));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void getCollissionShapes(@Nullable Entity entity, ShapeContext context, Consumer<VoxelShape> output) {
|
|
||||||
if (entity == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity.isCollidable()) {
|
|
||||||
output.accept(VoxelShapes.cuboid(entity.getBoundingBox()));
|
|
||||||
} else if (entity instanceof FallingBlockEntity) {
|
|
||||||
BlockPos pos = entity.getBlockPos();
|
|
||||||
output.accept(((FallingBlockEntity) entity).getBlockState()
|
|
||||||
.getCollisionShape(entity.world, entity.getBlockPos(), context)
|
|
||||||
.offset(pos.getX(), pos.getY(), pos.getZ())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<VoxelShape> getColissonShapes(@Nullable Entity entity, WorldAccess world, Box box) {
|
|
||||||
List<VoxelShape> shapes = new ArrayList<>();
|
|
||||||
ShapeContext ctx = entity == null ? ShapeContext.absent() : ShapeContext.of(entity);
|
|
||||||
VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D));
|
|
||||||
|
|
||||||
world.getOtherEntities(entity, box.expand(0.5), e -> {
|
|
||||||
Caster.of(e).flatMap(c -> c.getSpellSlot().get(SpellPredicate.IS_DISGUISE, false)).ifPresent(p -> {
|
|
||||||
p.getDisguise().getCollissionShapes(ctx, shape -> {
|
|
||||||
if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) {
|
|
||||||
shapes.add(shape);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
return shapes;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.minelittlepony.unicopia.entity.collision;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
|
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
|
||||||
|
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.FallingBlockEntity;
|
||||||
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Box;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
|
||||||
|
public class EntityCollisions {
|
||||||
|
|
||||||
|
public static void getCollissionShapes(@Nullable Entity entity, ShapeContext context, Consumer<VoxelShape> output) {
|
||||||
|
if (entity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.isCollidable()) {
|
||||||
|
output.accept(VoxelShapes.cuboid(entity.getBoundingBox()));
|
||||||
|
if (entity instanceof ComplexCollidable collidable) {
|
||||||
|
collidable.getCollissionShapes(context, output);
|
||||||
|
}
|
||||||
|
} else if (entity instanceof FallingBlockEntity) {
|
||||||
|
BlockPos pos = entity.getBlockPos();
|
||||||
|
output.accept(((FallingBlockEntity) entity).getBlockState()
|
||||||
|
.getCollisionShape(entity.world, entity.getBlockPos(), context)
|
||||||
|
.offset(pos.getX(), pos.getY(), pos.getZ())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<VoxelShape> getColissonShapes(@Nullable Entity entity, WorldAccess world, Box box) {
|
||||||
|
ShapeContext ctx = entity == null ? ShapeContext.absent() : ShapeContext.of(entity);
|
||||||
|
return collectCollisionBoxes(box, collector -> {
|
||||||
|
world.getOtherEntities(entity, box.expand(50), e -> {
|
||||||
|
Caster.of(e).flatMap(c -> c.getSpellSlot().get(SpellPredicate.IS_DISGUISE, false)).ifPresent(p -> {
|
||||||
|
p.getDisguise().getCollissionShapes(ctx, collector);
|
||||||
|
});
|
||||||
|
if (e instanceof ComplexCollidable collidable) {
|
||||||
|
collidable.getCollissionShapes(ctx, collector);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<VoxelShape> collectCollisionBoxes(Box box, Consumer<Consumer<VoxelShape>> generator) {
|
||||||
|
List<VoxelShape> shapes = new ArrayList<>();
|
||||||
|
VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D));
|
||||||
|
generator.accept(shape -> {
|
||||||
|
if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) {
|
||||||
|
shapes.add(shape);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return shapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ComplexCollidable {
|
||||||
|
void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.BlockDestructionManager;
|
import com.minelittlepony.unicopia.BlockDestructionManager;
|
||||||
import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
|
import com.minelittlepony.unicopia.entity.collision.EntityCollisions;
|
||||||
import com.minelittlepony.unicopia.entity.duck.RotatedView;
|
import com.minelittlepony.unicopia.entity.duck.RotatedView;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
@ -51,7 +51,7 @@ abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source
|
||||||
@Override
|
@Override
|
||||||
public List<VoxelShape> getEntityCollisions(@Nullable Entity entity, Box box) {
|
public List<VoxelShape> getEntityCollisions(@Nullable Entity entity, Box box) {
|
||||||
if (box.getAverageSideLength() >= 1.0E-7D) {
|
if (box.getAverageSideLength() >= 1.0E-7D) {
|
||||||
List<VoxelShape> shapes = EntityAppearance.getColissonShapes(entity, this, box);
|
List<VoxelShape> shapes = EntityCollisions.getColissonShapes(entity, this, box);
|
||||||
if (!shapes.isEmpty()) {
|
if (!shapes.isEmpty()) {
|
||||||
return Stream.concat(shapes.stream(), WorldAccess.super.getEntityCollisions(entity, box).stream()).toList();
|
return Stream.concat(shapes.stream(), WorldAccess.super.getEntityCollisions(entity, box).stream()).toList();
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3 KiB |
Loading…
Reference in a new issue