- Fix hot air balloons not orienting correctly when placed
- add sandbags that you interact with to steer them - fix various hitbox jankyness - exclude spectators from hot air balloon collision checks
1
assets/models/hanging_sandbag.bbmodel
Normal file
33
assets/models/hanging_sandbag.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Made with Blockbench 4.9.4
|
||||||
|
// Exported for Minecraft version 1.17+ for Yarn
|
||||||
|
// Paste this class into your mod and generate all required imports
|
||||||
|
public class hanging_sandbag extends EntityModel<Entity> {
|
||||||
|
private final ModelPart root;
|
||||||
|
private final ModelPart bag;
|
||||||
|
private final ModelPart cube_r1;
|
||||||
|
private final ModelPart cube_r2;
|
||||||
|
public hanging_sandbag(ModelPart root) {
|
||||||
|
this.root = root.getChild("root");
|
||||||
|
}
|
||||||
|
public static TexturedModelData getTexturedModelData() {
|
||||||
|
ModelData modelData = new ModelData();
|
||||||
|
ModelPartData modelPartData = modelData.getRoot();
|
||||||
|
ModelPartData root = modelPartData.addChild("root", ModelPartBuilder.create().uv(16, 19).cuboid(-0.5F, 0.0F, -0.5F, 1.0F, 9.0F, 1.0F, new Dilation(0.0F)), ModelTransform.pivot(0.0F, 24.0F, 0.0F));
|
||||||
|
|
||||||
|
ModelPartData bag = root.addChild("bag", ModelPartBuilder.create().uv(0, 0).cuboid(-3.0F, 1.0F, -3.0F, 6.0F, 7.0F, 6.0F, new Dilation(0.0F))
|
||||||
|
.uv(12, 14).cuboid(-2.0F, 0.0F, -2.0F, 4.0F, 1.0F, 4.0F, new Dilation(0.0F))
|
||||||
|
.uv(0, 13).cuboid(-2.0F, 8.0F, -2.0F, 4.0F, 1.0F, 4.0F, new Dilation(0.0F)), ModelTransform.pivot(0.0F, 9.0F, 0.0F));
|
||||||
|
|
||||||
|
ModelPartData cube_r1 = bag.addChild("cube_r1", ModelPartBuilder.create().uv(0, 14).cuboid(0.0F, 8.0F, -2.0F, 0.0F, 4.0F, 4.0F, new Dilation(0.0F)), ModelTransform.of(0.0F, 1.0F, 0.0F, 0.0F, -0.7854F, 0.0F));
|
||||||
|
|
||||||
|
ModelPartData cube_r2 = bag.addChild("cube_r2", ModelPartBuilder.create().uv(0, 14).cuboid(0.0F, 8.0F, -2.0F, 0.0F, 4.0F, 4.0F, new Dilation(0.0F)), ModelTransform.of(0.0F, 1.0F, 0.0F, 0.0F, 0.7854F, 0.0F));
|
||||||
|
return TexturedModelData.of(modelData, 32, 32);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setAngles(Entity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void render(MatrixStack matrices, VertexConsumer vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha) {
|
||||||
|
root.render(matrices, vertexConsumer, light, overlay, red, green, blue, alpha);
|
||||||
|
}
|
||||||
|
}
|
BIN
assets/models/hanging_sandbag.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
|
@ -1,113 +0,0 @@
|
||||||
{
|
|
||||||
"textures": {
|
|
||||||
"top": "blocks/hay_block_top",
|
|
||||||
"particle": "blocks/hay_block_side",
|
|
||||||
"side": "blocks/hay_block_side"
|
|
||||||
},
|
|
||||||
"elements": [
|
|
||||||
{
|
|
||||||
"name": "bottom_south_east",
|
|
||||||
"from": [8, 0, 8],
|
|
||||||
"to": [16, 8, 16],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
|
||||||
"east": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
|
||||||
"south": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
|
||||||
"west": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
|
||||||
"up": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
|
||||||
"down": {"uv": [8, 0, 16, 8], "texture": "#top"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "top_south_east",
|
|
||||||
"from": [8, 8, 8],
|
|
||||||
"to": [16, 16, 16],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
|
||||||
"east": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
|
||||||
"south": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
|
||||||
"west": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
|
||||||
"up": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
|
||||||
"down": {"uv": [8, 0, 16, 8], "texture": "#top"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "bottom_north_east",
|
|
||||||
"from": [8, 0, 0],
|
|
||||||
"to": [16, 8, 8],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
|
||||||
"east": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
|
||||||
"south": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
|
||||||
"west": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
|
||||||
"up": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
|
||||||
"down": {"uv": [8, 8, 16, 16], "texture": "#top"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "top_north_east",
|
|
||||||
"from": [8, 8, 0],
|
|
||||||
"to": [16, 16, 8],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
|
||||||
"east": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
|
||||||
"south": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
|
||||||
"west": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
|
||||||
"up": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
|
||||||
"down": {"uv": [8, 8, 16, 16], "texture": "#top"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "bottom_south_west",
|
|
||||||
"from": [0, 0, 8],
|
|
||||||
"to": [8, 8, 16],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
|
||||||
"east": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
|
||||||
"south": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
|
||||||
"west": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
|
||||||
"up": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
|
||||||
"down": {"uv": [0, 0, 8, 8], "texture": "#top"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "top_south_west",
|
|
||||||
"from": [0, 8, 8],
|
|
||||||
"to": [8, 16, 16],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
|
||||||
"east": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
|
||||||
"south": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
|
||||||
"west": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
|
||||||
"up": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
|
||||||
"down": {"uv": [0, 0, 8, 8], "texture": "#top"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "bottom_north_west",
|
|
||||||
"from": [0, 0, 0],
|
|
||||||
"to": [8, 8, 8],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
|
||||||
"east": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
|
||||||
"south": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
|
||||||
"west": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
|
||||||
"up": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
|
||||||
"down": {"uv": [0, 8, 8, 16], "texture": "#top"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "top_north_west",
|
|
||||||
"from": [0, 8, 0],
|
|
||||||
"to": [8, 16, 8],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
|
||||||
"east": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
|
||||||
"south": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
|
||||||
"west": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
|
||||||
"up": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
|
||||||
"down": {"uv": [0, 8, 8, 16], "texture": "#top"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ import java.util.List;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity;
|
import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.model.*;
|
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;
|
||||||
|
@ -14,26 +15,37 @@ import net.minecraft.util.math.MathHelper;
|
||||||
public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
||||||
|
|
||||||
private final ModelPart root;
|
private final ModelPart root;
|
||||||
|
private ModelPart main;
|
||||||
|
|
||||||
private float inflation;
|
private float inflation;
|
||||||
|
|
||||||
private boolean isBurner;
|
private boolean isBurner;
|
||||||
private boolean isBalloon;
|
private boolean isBalloon;
|
||||||
|
private boolean isSandbags;
|
||||||
|
|
||||||
private final List<ModelPart> ropes;
|
private final List<ModelPart> ropes;
|
||||||
|
private final List<ModelPart> sandbags;
|
||||||
|
|
||||||
public AirBalloonEntityModel(ModelPart root) {
|
public AirBalloonEntityModel(ModelPart root) {
|
||||||
this.root = root;
|
this.root = root;
|
||||||
isBurner = root.hasChild("burner");
|
isBurner = root.hasChild("burner");
|
||||||
|
isSandbags = root.hasChild("sandbag_ne");
|
||||||
isBalloon = root.hasChild("canopy");
|
isBalloon = root.hasChild("canopy");
|
||||||
|
|
||||||
if (isBurner || isBalloon) {
|
if (isBurner || isBalloon) {
|
||||||
ModelPart part = root.getChild(isBalloon ? "canopy" : "burner");
|
main = root.getChild(isBalloon ? "canopy" : "burner");
|
||||||
ropes = List.of(part.getChild("rope_a"), part.getChild("rope_b"), part.getChild("rope_c"),
|
ropes = List.of(
|
||||||
part.getChild("rope_d"));
|
(isBurner ? root : main).getChild("rope_a"), (isBurner ? root : main).getChild("rope_b"),
|
||||||
|
(isBurner ? root : main).getChild("rope_c"), (isBurner ? root : main).getChild("rope_d")
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
ropes = List.of();
|
ropes = List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sandbags = isSandbags ? List.of(
|
||||||
|
root.getChild("sandbag_nw"), root.getChild("sandbag_sw"),
|
||||||
|
root.getChild("sandbag_ne"), root.getChild("sandbag_se")
|
||||||
|
) : List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TexturedModelData getBasketModelData() {
|
public static TexturedModelData getBasketModelData() {
|
||||||
|
@ -56,12 +68,34 @@ public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
||||||
public static TexturedModelData getBurnerModelData() {
|
public static TexturedModelData getBurnerModelData() {
|
||||||
ModelData modelData = new ModelData();
|
ModelData modelData = new ModelData();
|
||||||
ModelPartData root = modelData.getRoot();
|
ModelPartData root = modelData.getRoot();
|
||||||
|
root.addChild("burner", ModelPartBuilder.create().uv(8, 0).cuboid(-5.5F, -47, -5.5F, 11, 15, 11, Dilation.NONE), ModelTransform.pivot(0, 24, 0));
|
||||||
|
float angle = 0.37854F;
|
||||||
|
float half = MathHelper.HALF_PI;
|
||||||
|
root.addChild("rope_d", ModelPartBuilder.create().cuboid(0, -68, 0, 2, 66, 2, Dilation.NONE), ModelTransform.of(-0, -20, -0, angle, 0, -angle));
|
||||||
|
root.addChild("rope_c", ModelPartBuilder.create().cuboid(0, -68, 0, 2, 66, 2, Dilation.NONE), ModelTransform.of(-0, -20, -0, -angle, 0, -angle));
|
||||||
|
root.addChild("rope_b", ModelPartBuilder.create().cuboid(0, -68, 0, 2, 66, 2, Dilation.NONE), ModelTransform.of( 0, -20, 0, -angle, 0, angle));
|
||||||
|
root.addChild("rope_a", ModelPartBuilder.create().cuboid(0, -68, 0, 2, 66, 2, Dilation.NONE), ModelTransform.of( 0, -20, 0, angle, 0, angle));
|
||||||
|
|
||||||
ModelPartData burner = root.addChild("burner", ModelPartBuilder.create().uv(8, 0).cuboid(-6, -47, -6, 11, 15, 11, Dilation.NONE), ModelTransform.pivot(0, 24, 0));
|
root.addChild("strut_a", ModelPartBuilder.create()
|
||||||
burner.addChild("rope_d", ModelPartBuilder.create().cuboid(-2, -68, 0, 2, 68, 2, Dilation.NONE), ModelTransform.of(-5, -46, -6, 0.7854F, 0, -0.7854F));
|
.cuboid(-27, -40, -30, 2, 40, 2, Dilation.NONE)
|
||||||
burner.addChild("rope_c", ModelPartBuilder.create().cuboid(-2, -68, 0, 2, 68, 2, Dilation.NONE), ModelTransform.of(-4, -44, 3, -0.7854F, 0, -0.7854F));
|
.cuboid(-27, 0, -30, 2, 40, 2, Dilation.NONE)
|
||||||
burner.addChild("rope_b", ModelPartBuilder.create().cuboid(-2, -68, 0, 2, 68, 2, Dilation.NONE), ModelTransform.of(5, -46, 1, -0.7854F, 0, 0.7854F));
|
.cuboid( 27, -40, -30, 2, 40, 2, Dilation.NONE)
|
||||||
burner.addChild("rope_a", ModelPartBuilder.create().cuboid(-2, -68, 0, 2, 68, 2, Dilation.NONE), ModelTransform.of(5, -45, -6, 0.7854F, 0, 0.7854F));
|
.cuboid( 27, 0, -30, 2, 40, 2, Dilation.NONE)
|
||||||
|
|
||||||
|
.cuboid(-27, -40, 26, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid(-27, 0, 26, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid( 27, -40, 26, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid( 27, 0, 26, 2, 40, 2, Dilation.NONE), ModelTransform.of(0, -80, 0, half, 0, 0));
|
||||||
|
root.addChild("strut_b", ModelPartBuilder.create()
|
||||||
|
.cuboid(-27, -40, -20, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid(-27, 0, -20, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid( 27, -40, -20, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid( 27, 0, -20, 2, 40, 2, Dilation.NONE)
|
||||||
|
|
||||||
|
.cuboid(-27, -40, 30, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid(-27, 0, 30, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid( 27, -40, 30, 2, 40, 2, Dilation.NONE)
|
||||||
|
.cuboid( 27, 0, 30, 2, 40, 2, Dilation.NONE), ModelTransform.of(0, -80, 0, half, half, 0));
|
||||||
return TexturedModelData.of(modelData, 64, 128);
|
return TexturedModelData.of(modelData, 64, 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,14 +110,40 @@ public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
||||||
return TexturedModelData.of(modelData, 512, 256);
|
return TexturedModelData.of(modelData, 512, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TexturedModelData getSandbagsModelData() {
|
||||||
|
ModelData modelData = new ModelData();
|
||||||
|
ModelPartData root = modelData.getRoot();
|
||||||
|
float offset = 40;
|
||||||
|
getHangingBagModelData("sandbag_ne", root, -offset, -offset);
|
||||||
|
getHangingBagModelData("sandbag_nw", root, -offset, offset);
|
||||||
|
getHangingBagModelData("sandbag_se", root, offset, -offset);
|
||||||
|
getHangingBagModelData("sandbag_sw", root, offset, offset);
|
||||||
|
return TexturedModelData.of(modelData, 32, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void getHangingBagModelData(String name, ModelPartData root, float x, float z) {
|
||||||
|
ModelPartData bag = root.addChild(name, ModelPartBuilder.create()
|
||||||
|
.uv(16, 19).cuboid(-0.5F, 0, -0.5F, 1, 9, 1, Dilation.NONE), ModelTransform.pivot(x, -35, z));
|
||||||
|
ModelPartData knot = bag.addChild("knot", ModelPartBuilder.create()
|
||||||
|
.uv(0, 0).cuboid(-3, 1, -3, 6, 7, 6, Dilation.NONE)
|
||||||
|
.uv(12, 14).cuboid(-2, 0, -2, 4, 1, 4, Dilation.NONE)
|
||||||
|
.uv(0, 13).cuboid(-2, 8, -2, 4, 1, 4, Dilation.NONE), ModelTransform.pivot(0, 9, 0));
|
||||||
|
knot.addChild("cube_r1", ModelPartBuilder.create().uv(8, 14).cuboid(0, 8, -2, 0, 4, 4, Dilation.NONE), ModelTransform.of(0, 1, 0, 0, -0.7854F, 0));
|
||||||
|
knot.addChild("cube_r2", ModelPartBuilder.create().uv(8, 14).cuboid(0, 8, -2, 0, 4, 4, Dilation.NONE), ModelTransform.of(0, 1, 0, 0, 0.7854F, 0));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAngles(AirBalloonEntity entity, float tickDelta, float limbSwingAmount, float ageInTicks,
|
public void setAngles(AirBalloonEntity entity, float limbDistance, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
|
||||||
float netHeadYaw, float headPitch) {
|
float tickDelta = MinecraftClient.getInstance().getTickDelta();
|
||||||
inflation = entity.getInflation(tickDelta);
|
inflation = entity.getInflation(tickDelta);
|
||||||
|
|
||||||
if (isBurner || isBalloon) {
|
root.yaw = MathHelper.PI;
|
||||||
root.roll = MathHelper.clamp((float) (entity.getX() - entity.lastRenderX), -0.5F, 0.5F);
|
|
||||||
root.pitch = MathHelper.clamp((float) (entity.getZ() - entity.lastRenderZ), -0.5F, 0.5F);
|
float burnerWiggleProgress = entity.getBurner().getPullProgress(tickDelta);
|
||||||
|
|
||||||
|
if (isBurner || isBalloon || isSandbags) {
|
||||||
|
root.roll = MathHelper.clamp(entity.getXVelocity(tickDelta), -0.5F, 0.5F);
|
||||||
|
root.pitch = MathHelper.clamp(entity.getZVelocity(tickDelta), -0.5F, 0.5F);
|
||||||
if (entity.isLeashed()) {
|
if (entity.isLeashed()) {
|
||||||
root.roll *= -1;
|
root.roll *= -1;
|
||||||
root.pitch *= -1;
|
root.pitch *= -1;
|
||||||
|
@ -93,27 +153,44 @@ public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
||||||
root.roll = 0;
|
root.roll = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ModelPart rope : ropes) {
|
ropes.forEach(ModelPart::resetTransform);
|
||||||
rope.resetTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBurner) {
|
if (isBurner) {
|
||||||
boolean lifted = inflation > 0.8F;
|
boolean lifted = inflation > 0.8F;
|
||||||
root.pivotY = 32 * (1 - inflation);
|
root.pivotY = 32 * (1 - inflation) - (9 * inflation);
|
||||||
root.pivotX = inflation * MathHelper.sin(limbSwingAmount + entity.age / 5F) / 4F;
|
root.pivotX = inflation * MathHelper.sin(limbSwingAmount + entity.age / 5F) / 4F;
|
||||||
ropes.forEach(rope -> {
|
ropes.forEach(rope -> {
|
||||||
rope.visible = lifted;
|
rope.visible = lifted;
|
||||||
rope.pitch *= 0.125;
|
|
||||||
rope.roll *= 0.125;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
root.pivotX += burnerWiggleProgress * MathHelper.sin((entity.age + tickDelta)) * 2.5F;
|
||||||
|
root.pivotX += burnerWiggleProgress * MathHelper.cos((entity.age + tickDelta)) * 2.5F;
|
||||||
|
root.pivotY += burnerWiggleProgress * 7;
|
||||||
}
|
}
|
||||||
if (isBalloon) {
|
if (isBalloon || isSandbags) {
|
||||||
root.pivotY = 0;
|
root.pivotY = burnerWiggleProgress * 3;
|
||||||
root.pivotX = inflation * MathHelper.cos(limbSwingAmount + entity.age / 5F) / 4F;
|
root.pivotX = inflation * MathHelper.cos(limbSwingAmount + entity.age / 5F) / 4F;
|
||||||
if (entity.getBasketType().isOf(BoatEntity.Type.BAMBOO)) {
|
if (entity.getBasketType().isOf(BoatEntity.Type.BAMBOO)) {
|
||||||
ropes.forEach(rope -> rope.pivotY = 0);
|
ropes.forEach(rope -> rope.pivotY = 0);
|
||||||
} else {
|
}
|
||||||
ropes.forEach(ModelPart::resetTransform);
|
}
|
||||||
|
|
||||||
|
if (isSandbags) {
|
||||||
|
float cosWiggle = MathHelper.cos(limbSwingAmount + entity.age / 5F) / 80F;
|
||||||
|
float sinWiggle = MathHelper.sin(limbSwingAmount + entity.age / 5F) / 80F;
|
||||||
|
for (int i = 0; i < sandbags.size(); i++) {
|
||||||
|
ModelPart bag = sandbags.get(i);
|
||||||
|
float pullProgress = entity.getSandbag(i).getPullProgress(tickDelta);
|
||||||
|
bag.resetTransform();
|
||||||
|
bag.pitch -= root.pitch * 2.5F * (1 + pullProgress) + cosWiggle;
|
||||||
|
bag.roll -= root.roll * 2.5F * (1 + pullProgress) + sinWiggle;
|
||||||
|
if (entity.isLeashed()) {
|
||||||
|
bag.roll *= -1;
|
||||||
|
bag.pitch *= -1;
|
||||||
|
}
|
||||||
|
float pullAmount = 2 + (2 * pullProgress);
|
||||||
|
bag.yScale = pullAmount;
|
||||||
|
bag.getChild("knot").yScale = 1/pullAmount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +215,16 @@ public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
|
||||||
if (i == 0 || i == 1) {
|
if (i == 0 || i == 1) {
|
||||||
rope.pivotX += 5 * rollRatio;
|
rope.pivotX += 5 * rollRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isBalloon) {
|
||||||
|
double speed = Math.abs(entity.getVelocity().getY()) * 3F;
|
||||||
|
|
||||||
|
rope.zScale = MathHelper.clamp((float)speed, 0.25F, 1F);
|
||||||
|
rope.xScale = 0.001F;
|
||||||
|
} else {
|
||||||
|
rope.xScale = 0.3F;
|
||||||
|
rope.zScale = 0.3F;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package com.minelittlepony.unicopia.client.render.entity;
|
package com.minelittlepony.unicopia.client.render.entity;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.Unicopia;
|
import com.minelittlepony.unicopia.Unicopia;
|
||||||
|
import com.minelittlepony.unicopia.entity.collision.MultiBox;
|
||||||
import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity;
|
import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity;
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
@ -17,15 +19,22 @@ import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.item.Items;
|
import net.minecraft.item.Items;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.Box;
|
|
||||||
|
|
||||||
public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity, AirBalloonEntityModel> {
|
public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity, AirBalloonEntityModel> {
|
||||||
public AirBalloonEntityRenderer(EntityRendererFactory.Context context) {
|
public AirBalloonEntityRenderer(EntityRendererFactory.Context context) {
|
||||||
super(context, new AirBalloonEntityModel(AirBalloonEntityModel.getBasketModelData().createModel()), 0);
|
super(context, new AirBalloonEntityModel(AirBalloonEntityModel.getBasketModelData().createModel()), 0);
|
||||||
addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getBurnerModelData().createModel()), this, AirBalloonEntity::hasBurner, e -> {
|
addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getBurnerModelData().createModel()), this,
|
||||||
|
AirBalloonEntity::hasBurner, e -> {
|
||||||
return getComponentTexture(e.getStackInHand(Hand.MAIN_HAND).isOf(Items.SOUL_LANTERN) ? "soul_burner" : "burner");
|
return getComponentTexture(e.getStackInHand(Hand.MAIN_HAND).isOf(Items.SOUL_LANTERN) ? "soul_burner" : "burner");
|
||||||
}));
|
}, (light, entity) -> entity.isAscending() ? 0xFF00FF : light));
|
||||||
addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getCanopyModelData().createModel()), this, AirBalloonEntity::hasBalloon, e -> getComponentTexture("canopy/" + e.getDesign().asString())));
|
addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getCanopyModelData().createModel()), this,
|
||||||
|
AirBalloonEntity::hasBalloon,
|
||||||
|
e -> getComponentTexture("canopy/" + e.getDesign().asString()),
|
||||||
|
(light, entity) -> entity.hasBurner() && entity.isAscending() ? light | 0x00005F : light)
|
||||||
|
);
|
||||||
|
addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getSandbagsModelData().createModel()),
|
||||||
|
this, e -> e.hasBalloon() && e.getInflation(1) >= 1, e -> getComponentTexture("sandbags"),
|
||||||
|
(light, entity) -> entity.hasBurner() && entity.isAscending() ? light | 0x00003F : light));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,9 +42,9 @@ public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity
|
||||||
super.render(entity, yaw, tickDelta, matrices, vertices, light);
|
super.render(entity, yaw, tickDelta, matrices, vertices, light);
|
||||||
|
|
||||||
if (MinecraftClient.getInstance().getEntityRenderDispatcher().shouldRenderHitboxes() && !entity.isInvisible() && !MinecraftClient.getInstance().hasReducedDebugInfo()) {
|
if (MinecraftClient.getInstance().getEntityRenderDispatcher().shouldRenderHitboxes() && !entity.isInvisible() && !MinecraftClient.getInstance().hasReducedDebugInfo()) {
|
||||||
for (Box box : entity.getBoundingBoxes()) {
|
MultiBox.forEach(entity.getBoundingBox(), box -> {
|
||||||
WorldRenderer.drawBox(matrices, vertices.getBuffer(RenderLayer.getLines()), box.offset(entity.getPos().multiply(-1)), 1.0f, 1.0f, 1.0f, 1.0f);
|
WorldRenderer.drawBox(matrices, vertices.getBuffer(RenderLayer.getLines()), box.offset(entity.getPos().multiply(-1)), 1, 1, 1, 1);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,22 +66,30 @@ public class AirBalloonEntityRenderer extends MobEntityRenderer<AirBalloonEntity
|
||||||
private final AirBalloonEntityModel model;
|
private final AirBalloonEntityModel model;
|
||||||
private final Predicate<AirBalloonEntity> visibilityTest;
|
private final Predicate<AirBalloonEntity> visibilityTest;
|
||||||
private final Function<AirBalloonEntity, Identifier> textureFunc;
|
private final Function<AirBalloonEntity, Identifier> textureFunc;
|
||||||
|
private final BiFunction<Integer, AirBalloonEntity, Integer> lightFunc;
|
||||||
|
|
||||||
public BalloonFeature(AirBalloonEntityModel model,
|
public BalloonFeature(AirBalloonEntityModel model,
|
||||||
FeatureRendererContext<AirBalloonEntity, AirBalloonEntityModel> context,
|
FeatureRendererContext<AirBalloonEntity, AirBalloonEntityModel> context,
|
||||||
Predicate<AirBalloonEntity> visibilityTest,
|
Predicate<AirBalloonEntity> visibilityTest,
|
||||||
Function<AirBalloonEntity, Identifier> textureFunc) {
|
Function<AirBalloonEntity, Identifier> textureFunc,
|
||||||
|
BiFunction<Integer, AirBalloonEntity, Integer> lightFunc) {
|
||||||
super(context);
|
super(context);
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.visibilityTest = visibilityTest;
|
this.visibilityTest = visibilityTest;
|
||||||
this.textureFunc = textureFunc;
|
this.textureFunc = textureFunc;
|
||||||
|
this.lightFunc = lightFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, AirBalloonEntity entity,
|
public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, AirBalloonEntity entity,
|
||||||
float limbAngle, float limbDistance, float tickDelta, float animationProgress, float yaw, float pitch) {
|
float limbAngle, float limbDistance, float tickDelta, float animationProgress, float yaw, float pitch) {
|
||||||
if (visibilityTest.test(entity)) {
|
if (visibilityTest.test(entity)) {
|
||||||
render(getModel(), model, textureFunc.apply(entity), matrices, vertices, light, entity, limbAngle, limbDistance, 0, yaw, pitch, tickDelta, 1, 1, 1);
|
Identifier texture = textureFunc.apply(entity);
|
||||||
|
var model = this.model;
|
||||||
|
if (texture.getPath().indexOf("sandbags") != -1) {
|
||||||
|
model = new AirBalloonEntityModel(AirBalloonEntityModel.getSandbagsModelData().createModel());
|
||||||
|
}
|
||||||
|
render(getModel(), model, texture, matrices, vertices, lightFunc.apply(light, entity), entity, limbAngle, limbDistance, 0, yaw, pitch, tickDelta, 1, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.MovementType;
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
import net.minecraft.util.math.Box;
|
import net.minecraft.util.math.Box;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
@ -124,6 +125,9 @@ public class Transportation<T extends LivingEntity> implements Tickable {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Box getVehicleBox() {
|
private Box getVehicleBox() {
|
||||||
|
if (!EntityPredicates.EXCEPT_SPECTATOR.test(living.asEntity())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (vehicle == null) {
|
if (vehicle == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.entity.collision;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -24,6 +25,12 @@ public final class MultiBox extends Box {
|
||||||
return box instanceof MultiBox m ? m.first : box;
|
return box instanceof MultiBox m ? m.first : box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void forEach(Box box, Consumer<Box> consumer) {
|
||||||
|
if (box instanceof MultiBox m) {
|
||||||
|
m.children.forEach(consumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private MultiBox(Box first, BoxChildren children) {
|
private MultiBox(Box first, BoxChildren children) {
|
||||||
super(first.minX, first.minY, first.minZ, first.maxX, first.maxY, first.maxZ);
|
super(first.minX, first.minY, first.minZ, first.maxX, first.maxY, first.maxZ);
|
||||||
this.first = unbox(first);
|
this.first = unbox(first);
|
||||||
|
@ -148,6 +155,12 @@ public final class MultiBox extends Box {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void forEach(Consumer<Box> consumer) {
|
||||||
|
for (int i = 0; i < children.length; i++) {
|
||||||
|
consumer.accept(children[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return toString.get();
|
return toString.get();
|
||||||
|
|
|
@ -39,10 +39,10 @@ import java.util.function.Function;
|
||||||
import java.util.function.IntFunction;
|
import java.util.function.IntFunction;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EquineContext;
|
import com.minelittlepony.unicopia.EquineContext;
|
||||||
import com.minelittlepony.unicopia.Race;
|
import com.minelittlepony.unicopia.Race;
|
||||||
import com.minelittlepony.unicopia.USounds;
|
import com.minelittlepony.unicopia.USounds;
|
||||||
|
@ -65,6 +65,8 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
private static final TrackedData<String> BASKET_TYPE = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.STRING);
|
private static final TrackedData<String> BASKET_TYPE = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.STRING);
|
||||||
private static final TrackedData<Integer> BALLOON_DESIGN = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
private static final TrackedData<Integer> BALLOON_DESIGN = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||||
|
|
||||||
|
public static final byte STATUS_BURNER_INTERACT = (byte)105;
|
||||||
|
|
||||||
private static final Predicate<Entity> RIDER_PREDICATE = EntityPredicates.EXCEPT_SPECTATOR.and(e -> {
|
private static final Predicate<Entity> RIDER_PREDICATE = EntityPredicates.EXCEPT_SPECTATOR.and(e -> {
|
||||||
return !(e instanceof PlayerEntity p && p.getAbilities().flying);
|
return !(e instanceof PlayerEntity p && p.getAbilities().flying);
|
||||||
});
|
});
|
||||||
|
@ -73,9 +75,17 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
private int prevInflation;
|
private int prevInflation;
|
||||||
private Vec3d manualVelocity = Vec3d.ZERO;
|
private Vec3d manualVelocity = Vec3d.ZERO;
|
||||||
|
|
||||||
private int maxFuel = 100;
|
private int maxFuel = 10000;
|
||||||
private int fuel;
|
private int fuel;
|
||||||
|
|
||||||
|
private final Animatable[] sandbags = IntStream.range(0, 5).mapToObj(Animatable::new).toArray(Animatable[]::new);
|
||||||
|
private final Animatable burner = new Animatable(5);
|
||||||
|
|
||||||
|
private double prevXDelta;
|
||||||
|
private double xDelta;
|
||||||
|
private double prevZDelta;
|
||||||
|
private double zDelta;
|
||||||
|
|
||||||
public AirBalloonEntity(EntityType<? extends AirBalloonEntity> type, World world) {
|
public AirBalloonEntity(EntityType<? extends AirBalloonEntity> type, World world) {
|
||||||
super(type, world);
|
super(type, world);
|
||||||
intersectionChecked = true;
|
intersectionChecked = true;
|
||||||
|
@ -108,12 +118,20 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
dataTracker.set(BALLOON_DESIGN, design.ordinal());
|
dataTracker.set(BALLOON_DESIGN, design.ordinal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Animatable getSandbag(int index) {
|
||||||
|
return sandbags[MathHelper.clamp(index, 0, sandbags.length - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Animatable getBurner() {
|
||||||
|
return burner;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasBalloon() {
|
public boolean hasBalloon() {
|
||||||
return getDesign() != BalloonDesign.NONE;
|
return getDesign() != BalloonDesign.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasBurner() {
|
public boolean hasBurner() {
|
||||||
return !getStackInHand(Hand.MAIN_HAND).isEmpty();
|
return getHandItems() != null && !getStackInHand(Hand.MAIN_HAND).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getInflation(float tickDelta) {
|
public float getInflation(float tickDelta) {
|
||||||
|
@ -152,6 +170,14 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
return hasBalloon() && hasBurner() && getInflation() >= getMaxInflation();
|
return hasBalloon() && hasBurner() && getInflation() >= getMaxInflation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getXVelocity(float tickDelta) {
|
||||||
|
return (float)MathHelper.lerp(tickDelta, prevXDelta, xDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getZVelocity(float tickDelta) {
|
||||||
|
return (float)MathHelper.lerp(tickDelta, prevZDelta, zDelta);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
setAir(getMaxAir());
|
setAir(getMaxAir());
|
||||||
|
@ -179,8 +205,8 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
setInflation(inflation);
|
setInflation(inflation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fuel > -6 && age % 60 == 0) {
|
if (fuel > -6 && age % 2 == 0) {
|
||||||
fuel -= boosting ? 10 : 1;
|
fuel -= boosting ? 50 : 1;
|
||||||
if (fuel <= -6) {
|
if (fuel <= -6) {
|
||||||
setBoostTicks(0);
|
setBoostTicks(0);
|
||||||
setAscending(false);
|
setAscending(false);
|
||||||
|
@ -262,15 +288,26 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
setFireTicks(1);
|
setFireTicks(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (Animatable bag : sandbags) {
|
||||||
|
bag.tick();
|
||||||
|
}
|
||||||
|
burner.tick();
|
||||||
|
|
||||||
super.tick();
|
super.tick();
|
||||||
|
|
||||||
|
prevXDelta = xDelta;
|
||||||
|
prevZDelta = zDelta;
|
||||||
|
xDelta = getX() - prevX;
|
||||||
|
zDelta = getZ() - prevZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult interactAt(PlayerEntity player, Vec3d hitPos, Hand hand) {
|
public ActionResult interactAt(PlayerEntity player, Vec3d hitPos, Hand hand) {
|
||||||
ItemStack stack = player.getStackInHand(hand);
|
ItemStack stack = player.getStackInHand(hand);
|
||||||
|
|
||||||
if (hitPos.y > (3 * getInflation(1))) {
|
if (hasBalloon() && hasBurner()) {
|
||||||
if (hasBalloon() && hasBurner()) {
|
|
||||||
|
if (getBurnerBoundingBox().expand(0.7).contains(getPos().add(hitPos))) {
|
||||||
if (stack.isOf(Items.FLINT_AND_STEEL)) {
|
if (stack.isOf(Items.FLINT_AND_STEEL)) {
|
||||||
setAscending(!isAscending());
|
setAscending(!isAscending());
|
||||||
if (isAscending()) {
|
if (isAscending()) {
|
||||||
|
@ -281,31 +318,45 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
if (!player.isSneaky()) {
|
if (!player.isSneaky()) {
|
||||||
getWorld().emitGameEvent(player, GameEvent.ENTITY_INTERACT, getBlockPos());
|
getWorld().emitGameEvent(player, GameEvent.ENTITY_INTERACT, getBlockPos());
|
||||||
}
|
}
|
||||||
return ActionResult.SUCCESS;
|
burner.setPulling();
|
||||||
}
|
|
||||||
|
|
||||||
if (stack.isEmpty() && Math.abs(hitPos.x) > 1 && Math.abs(hitPos.z) > 1) {
|
|
||||||
double xPush = Math.signum(hitPos.x);
|
|
||||||
double zPush = Math.signum(hitPos.z);
|
|
||||||
if (!getWorld().isClient) {
|
|
||||||
manualVelocity = manualVelocity.add(0.3 * xPush, 0, 0.3 * zPush);
|
|
||||||
}
|
|
||||||
getWorld().playSound(null, getX() + hitPos.getX(), getY() + hitPos.getY(), getZ() + hitPos.getZ(), USounds.Vanilla.ENTITY_LEASH_KNOT_PLACE, getSoundCategory(), 1, 1);
|
|
||||||
if (!player.isSneaky()) {
|
|
||||||
getWorld().emitGameEvent(player, GameEvent.ENTITY_INTERACT, getBlockPos());
|
|
||||||
}
|
|
||||||
return ActionResult.SUCCESS;
|
return ActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack.isEmpty() && isAscending()) {
|
if (stack.isEmpty() && isAscending()) {
|
||||||
setBoostTicks(50);
|
setBoostTicks(50);
|
||||||
playSound(USounds.ENTITY_HOT_AIR_BALLOON_BOOST, 1, 1);
|
playSound(USounds.ENTITY_HOT_AIR_BALLOON_BOOST, 1, 1);
|
||||||
|
burner.setPulling();
|
||||||
if (!player.isSneaky()) {
|
if (!player.isSneaky()) {
|
||||||
getWorld().emitGameEvent(player, GameEvent.ENTITY_INTERACT, getBlockPos());
|
getWorld().emitGameEvent(player, GameEvent.ENTITY_INTERACT, getBlockPos());
|
||||||
}
|
}
|
||||||
return ActionResult.SUCCESS;
|
return ActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getInflation(1) >= 1) {
|
||||||
|
int xPush = (int)Math.signum(hitPos.x);
|
||||||
|
int zPush = (int)Math.signum(hitPos.z);
|
||||||
|
|
||||||
|
Vec3d absHitPos = getPos().add(hitPos);
|
||||||
|
|
||||||
|
if (stack.isEmpty() && MultiBox.unbox(getBoundingBox()).expand(0.5, 1, 0.5).offset(2 * xPush, 3, 2 * zPush).contains(absHitPos)) {
|
||||||
|
if (!getWorld().isClient) {
|
||||||
|
manualVelocity = manualVelocity.add(1.7 * xPush, 0, 1.7 * zPush);
|
||||||
|
}
|
||||||
|
getWorld().playSound(null, getX() + hitPos.getX(), getY() + hitPos.getY(), getZ() + hitPos.getZ(), USounds.Vanilla.ENTITY_LEASH_KNOT_PLACE, getSoundCategory(), 1, 1);
|
||||||
|
if (!player.isSneaky()) {
|
||||||
|
getWorld().emitGameEvent(player, GameEvent.ENTITY_INTERACT, getBlockPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3d interactCoordinate = new Vec3d(xPush, 0, zPush)
|
||||||
|
.rotateY((180 + getHorizontalFacing().asRotation()) * MathHelper.RADIANS_PER_DEGREE)
|
||||||
|
;
|
||||||
|
|
||||||
|
getSandbag(MathHelper.clamp((int)interactCoordinate.getX(), 0, 1) + MathHelper.clamp((int)interactCoordinate.getZ(), 0, 1) * 2).setPulling();
|
||||||
|
|
||||||
|
return ActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ActionResult.PASS;
|
return ActionResult.PASS;
|
||||||
|
@ -368,6 +419,7 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
if (!player.getAbilities().creativeMode) {
|
if (!player.getAbilities().creativeMode) {
|
||||||
stack.decrement(1);
|
stack.decrement(1);
|
||||||
}
|
}
|
||||||
|
burner.setPulling();
|
||||||
playSound(USounds.Vanilla.ENTITY_VILLAGER_YES, 1, 1);
|
playSound(USounds.Vanilla.ENTITY_VILLAGER_YES, 1, 1);
|
||||||
return ActionResult.SUCCESS;
|
return ActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -486,7 +538,26 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Box calculateBoundingBox() {
|
protected Box calculateBoundingBox() {
|
||||||
return MultiBox.of(super.calculateBoundingBox(), getBoundingBoxes());
|
List<Box> boxes = getBoundingBoxes();
|
||||||
|
Box box = super.calculateBoundingBox();
|
||||||
|
|
||||||
|
if (hasBalloon() && getInflation(1) > 0.999F) {
|
||||||
|
double horScale = -0.5;
|
||||||
|
// x+ z+
|
||||||
|
boxes.add(box.expand(horScale, 1, horScale).offset(2, 3, 2));
|
||||||
|
// x- z+
|
||||||
|
boxes.add(box.expand(horScale, 1, horScale).offset(-2, 3, 2));
|
||||||
|
|
||||||
|
// x+ z-
|
||||||
|
boxes.add(box.expand(horScale, 1, horScale).offset(2, 3, -2));
|
||||||
|
// x- z-
|
||||||
|
boxes.add(box.expand(horScale, 1, horScale).offset(-2, 3, -2));
|
||||||
|
}
|
||||||
|
if (hasBurner()) {
|
||||||
|
boxes.add(getBurnerBoundingBox());
|
||||||
|
}
|
||||||
|
|
||||||
|
return MultiBox.of(box, boxes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -509,6 +580,14 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
.expand(2.25, 3.7 * inflation, 2.25);
|
.expand(2.25, 3.7 * inflation, 2.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Box getBurnerBoundingBox() {
|
||||||
|
float inflation = getInflation(1);
|
||||||
|
float horScale = -0.9F;
|
||||||
|
return MultiBox.unbox(getBoundingBox())
|
||||||
|
.offset(0, 2.6F * inflation + 0.4F, 0)
|
||||||
|
.expand(horScale, 0.4, horScale);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Box> getGravityZoneBoxes() {
|
public List<Box> getGravityZoneBoxes() {
|
||||||
Box balloon = getBalloonBoundingBox().expand(0.001);
|
Box balloon = getBalloonBoundingBox().expand(0.001);
|
||||||
|
@ -528,29 +607,55 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
public List<Box> getBoundingBoxes() {
|
public List<Box> getBoundingBoxes() {
|
||||||
List<Box> boxes = new ArrayList<>();
|
List<Box> boxes = new ArrayList<>();
|
||||||
Box box = getInteriorBoundingBox();
|
Box box = getInteriorBoundingBox();
|
||||||
|
Box mainBox = MultiBox.unbox(getBoundingBox());
|
||||||
|
|
||||||
boxes.add(box);
|
boxes.add(box);
|
||||||
|
|
||||||
double wallheight = box.maxY + 0.72;
|
double wallheight = box.maxY + 0.72;
|
||||||
double wallThickness = 0.2;
|
double wallThickness = 0.3;
|
||||||
|
double halfDoorWidth = 0.5;
|
||||||
|
|
||||||
if (!getBasketType().isOf(BoatEntity.Type.BAMBOO)) {
|
if (!getBasketType().isOf(BoatEntity.Type.BAMBOO)) {
|
||||||
|
|
||||||
// front left (next to door)
|
// front left (next to door)
|
||||||
boxes.add(new Box(box.minX, box.minY, box.minZ, box.minX + wallThickness + 0.4, wallheight, box.minZ + wallThickness));
|
boxes.add(new Box(mainBox.minX, mainBox.minY, mainBox.minZ, mainBox.minX + wallThickness + halfDoorWidth, wallheight, box.minZ + wallThickness));
|
||||||
// front right (next to door)
|
// front right (next to door)
|
||||||
boxes.add(new Box(box.maxX - wallThickness - 0.4, box.minY, box.minZ, box.maxX, wallheight, box.minZ + wallThickness));
|
boxes.add(new Box(mainBox.maxX - wallThickness - halfDoorWidth, mainBox.minY, mainBox.minZ, mainBox.maxX, wallheight, box.minZ + wallThickness));
|
||||||
|
|
||||||
// back
|
// back
|
||||||
boxes.add(new Box(box.minX, box.minY, box.maxZ - wallThickness, box.maxX, wallheight, box.maxZ));
|
boxes.add(new Box(mainBox.minX, mainBox.minY, box.maxZ - wallThickness, mainBox.maxX, wallheight, mainBox.maxZ));
|
||||||
|
|
||||||
// left
|
// left
|
||||||
boxes.add(new Box(box.maxX - wallThickness, box.minY, box.minZ, box.maxX, wallheight, box.maxZ));
|
boxes.add(new Box(box.maxX - wallThickness, mainBox.minY, mainBox.minZ, mainBox.maxX, wallheight, mainBox.maxZ));
|
||||||
// right
|
// right
|
||||||
boxes.add(new Box(box.minX, box.minY, box.minZ, box.minX + wallThickness, wallheight, box.maxZ));
|
boxes.add(new Box(mainBox.minX, mainBox.minY, mainBox.minZ, box.minX + wallThickness, wallheight, mainBox.maxZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasBalloon() && getInflation(1) > 0.999F) {
|
if (hasBalloon() && getInflation(1) >= 1) {
|
||||||
boxes.add(getBalloonBoundingBox());
|
Box balloonBox = getBalloonBoundingBox();
|
||||||
|
boxes.add(balloonBox.withMinY(balloonBox.maxY - 0.5));
|
||||||
|
boxes.add(balloonBox.withMaxX(balloonBox.minX + 0.5));
|
||||||
|
boxes.add(balloonBox.withMinX(balloonBox.maxX - 0.5));
|
||||||
|
boxes.add(balloonBox.withMaxZ(balloonBox.minZ + 0.5));
|
||||||
|
boxes.add(balloonBox.withMinZ(balloonBox.maxZ - 0.5));
|
||||||
|
|
||||||
|
boxes.add(balloonBox.withMaxX(balloonBox.minX + 2).withMaxY(balloonBox.minY + 0.2));
|
||||||
|
boxes.add(balloonBox.withMinX(balloonBox.maxX - 2).withMaxY(balloonBox.minY + 0.2));
|
||||||
|
boxes.add(balloonBox.withMaxZ(balloonBox.minZ + 2).withMaxY(balloonBox.minY + 0.2));
|
||||||
|
boxes.add(balloonBox.withMinZ(balloonBox.maxZ - 2).withMaxY(balloonBox.minY + 0.2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float yaw = (180 - getHorizontalFacing().asRotation()) * MathHelper.RADIANS_PER_DEGREE;
|
||||||
|
if (yaw != 0) {
|
||||||
|
Vec3d center = getPos();
|
||||||
|
for (int i = 0; i < boxes.size(); i++) {
|
||||||
|
Box b = boxes.get(i);
|
||||||
|
Vec3d min = new Vec3d(b.minX, b.minY, b.minZ).subtract(center).rotateY(yaw).add(center);
|
||||||
|
Vec3d max = new Vec3d(b.maxX, b.maxY, b.maxZ).subtract(center).rotateY(yaw).add(center);
|
||||||
|
boxes.set(i, new Box(min.x, min.y, min.z, max.x, max.y, max.z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return boxes;
|
return boxes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,6 +679,10 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
}
|
}
|
||||||
|
|
||||||
private void movePassenger(Entity passenger, Vec3d movement) {
|
private void movePassenger(Entity passenger, Vec3d movement) {
|
||||||
|
if (!EntityPredicates.EXCEPT_SPECTATOR.test(passenger)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Living<?> living = Living.living(passenger);
|
Living<?> living = Living.living(passenger);
|
||||||
if (living != null) {
|
if (living != null) {
|
||||||
if (living.getPhysics().isGravityNegative()) {
|
if (living.getPhysics().isGravityNegative()) {
|
||||||
|
@ -625,10 +734,54 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
compound.putInt("fuel", fuel);
|
compound.putInt("fuel", fuel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleStatus(byte status) {
|
||||||
|
if (status >= 100 && status < 100 + sandbags.length) {
|
||||||
|
getSandbag(status % sandbags.length).setPulling();
|
||||||
|
} else if (status == STATUS_BURNER_INTERACT) {
|
||||||
|
} else {
|
||||||
|
super.handleStatus(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static boolean isBetween(double value, double min, double max) {
|
static boolean isBetween(double value, double min, double max) {
|
||||||
return value >= min && value <= max;
|
return value >= min && value <= max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class Animatable {
|
||||||
|
private final int id;
|
||||||
|
private int pullTicks;
|
||||||
|
private int prevPullTicks;
|
||||||
|
private boolean pulling;
|
||||||
|
|
||||||
|
public Animatable(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPulling() {
|
||||||
|
if (!getWorld().isClient) {
|
||||||
|
getWorld().sendEntityStatus(AirBalloonEntity.this, (byte)(100 + id));
|
||||||
|
}
|
||||||
|
pulling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPullProgress(float tickDelta) {
|
||||||
|
return MathHelper.lerp(tickDelta, (float)prevPullTicks, pullTicks) / 6F;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
prevPullTicks = pullTicks;
|
||||||
|
if (pulling && pullTicks < 6) {
|
||||||
|
pullTicks++;
|
||||||
|
} else {
|
||||||
|
pulling = false;
|
||||||
|
if (pullTicks > 0) {
|
||||||
|
pullTicks--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public enum BalloonDesign implements StringIdentifiable {
|
public enum BalloonDesign implements StringIdentifiable {
|
||||||
NONE,
|
NONE,
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class BasketItem extends Item implements Dispensable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hit.getType() == HitResult.Type.BLOCK) {
|
if (hit.getType() == HitResult.Type.BLOCK) {
|
||||||
return placeEntity(stack, world, hit.getPos().x, hit.getPos().y, hit.getPos().z, user.getYaw() + 180, user);
|
return placeEntity(stack, world, hit.getPos().x, hit.getPos().y, hit.getPos().z, user.getHorizontalFacing().asRotation(), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TypedActionResult.pass(stack);
|
return TypedActionResult.pass(stack);
|
||||||
|
@ -76,9 +76,11 @@ public class BasketItem extends Item implements Dispensable {
|
||||||
|
|
||||||
private TypedActionResult<ItemStack> placeEntity(ItemStack stack, World world, double x, double y, double z, float yaw, @Nullable PlayerEntity user) {
|
private TypedActionResult<ItemStack> placeEntity(ItemStack stack, World world, double x, double y, double z, float yaw, @Nullable PlayerEntity user) {
|
||||||
AirBalloonEntity entity = UEntities.AIR_BALLOON.create(world);
|
AirBalloonEntity entity = UEntities.AIR_BALLOON.create(world);
|
||||||
entity.updatePositionAndAngles(x, y, z, 0, 0);
|
yaw += 180;
|
||||||
|
entity.updatePositionAndAngles(x, y, z, yaw, 0);
|
||||||
entity.setHeadYaw(yaw);
|
entity.setHeadYaw(yaw);
|
||||||
entity.setBodyYaw(yaw);
|
entity.setBodyYaw(yaw);
|
||||||
|
entity.setYaw(yaw);
|
||||||
entity.setBasketType(type);
|
entity.setBasketType(type);
|
||||||
if (!world.isSpaceEmpty(entity, entity.getBoundingBox())) {
|
if (!world.isSpaceEmpty(entity, entity.getBoundingBox())) {
|
||||||
return TypedActionResult.fail(stack);
|
return TypedActionResult.fail(stack);
|
||||||
|
@ -92,7 +94,6 @@ public class BasketItem extends Item implements Dispensable {
|
||||||
stack.decrement(1);
|
stack.decrement(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TypedActionResult.success(stack, world.isClient());
|
return TypedActionResult.success(stack, world.isClient());
|
||||||
}
|
}
|
||||||
}
|
}
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 1.1 KiB |