diff --git a/assets/models/hanging_sandbag.bbmodel b/assets/models/hanging_sandbag.bbmodel new file mode 100644 index 00000000..463a3f37 --- /dev/null +++ b/assets/models/hanging_sandbag.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"4.9","model_format":"modded_entity","box_uv":true},"name":"hanging_sandbag","model_identifier":"","modded_entity_version":"Fabric 1.17+","modded_entity_flip_y":true,"visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"timeline_setups":[],"unhandled_root_fields":{},"resolution":{"width":32,"height":32},"elements":[{"name":"rope","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-0.5,-9,-0.5],"to":[0.5,0,0.5],"autouv":0,"color":7,"origin":[0,-22,0],"uv_offset":[16,19],"faces":{"north":{"uv":[17,20,18,29],"texture":0},"east":{"uv":[16,20,17,29],"texture":0},"south":{"uv":[19,20,20,29],"texture":0},"west":{"uv":[18,20,19,29],"texture":0},"up":{"uv":[18,20,17,19],"texture":0},"down":{"uv":[19,19,18,20],"texture":0}},"type":"cube","uuid":"023a3320-18c3-d968-3a13-56914da8e6f0"},{"name":"cube","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-3,-17,-3],"to":[3,-10,3],"autouv":0,"color":5,"origin":[0,-9,0],"faces":{"north":{"uv":[6,6,12,13],"texture":0},"east":{"uv":[0,6,6,13],"texture":0},"south":{"uv":[18,6,24,13],"texture":0},"west":{"uv":[12,6,18,13],"texture":0},"up":{"uv":[12,6,6,0],"texture":0},"down":{"uv":[18,0,12,6],"texture":0}},"type":"cube","uuid":"1ca3a675-33f5-744f-58f9-cf14867dcfb1"},{"name":"cube","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[0,-22,-2],"to":[0,-18,2],"autouv":0,"color":9,"rotation":[0,-45,0],"origin":[0,-10,0],"uv_offset":[0,14],"faces":{"north":{"uv":[4,18,4,22],"texture":0},"east":{"uv":[0,18,4,22],"texture":0},"south":{"uv":[8,18,8,22],"texture":0},"west":{"uv":[4,18,8,22],"texture":0},"up":{"uv":[4,18,4,14],"texture":0},"down":{"uv":[4,14,4,18],"texture":0}},"type":"cube","uuid":"5cc3052b-c843-eec8-9326-2bfd1b1fd435"},{"name":"cube","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[0,-22,-2],"to":[0,-18,2],"autouv":0,"color":9,"rotation":[0,45,0],"origin":[0,-10,0],"uv_offset":[0,14],"faces":{"north":{"uv":[4,18,4,22],"texture":0},"east":{"uv":[0,18,4,22],"texture":0},"south":{"uv":[8,18,8,22],"texture":0},"west":{"uv":[4,18,8,22],"texture":0},"up":{"uv":[4,18,4,14],"texture":0},"down":{"uv":[4,14,4,18],"texture":0}},"type":"cube","uuid":"9a732bc0-bf4d-cc97-85fb-674e15c88c5c"},{"name":"cube","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-2,-10,-2],"to":[2,-9,2],"autouv":0,"color":5,"origin":[0,-9,0],"uv_offset":[12,14],"faces":{"north":{"uv":[16,18,20,19],"texture":0},"east":{"uv":[12,18,16,19],"texture":0},"south":{"uv":[24,18,28,19],"texture":0},"west":{"uv":[20,18,24,19],"texture":0},"up":{"uv":[20,18,16,14],"texture":0},"down":{"uv":[24,14,20,18],"texture":0}},"type":"cube","uuid":"90ba7ded-8e83-43de-e4da-bb237f43bdd7"},{"name":"cube","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-2,-18,-2],"to":[2,-17,2],"autouv":0,"color":5,"origin":[0,-9,0],"uv_offset":[0,13],"faces":{"north":{"uv":[4,17,8,18],"texture":0},"east":{"uv":[0,17,4,18],"texture":0},"south":{"uv":[12,17,16,18],"texture":0},"west":{"uv":[8,17,12,18],"texture":0},"up":{"uv":[8,17,4,13],"texture":0},"down":{"uv":[12,13,8,17],"texture":0}},"type":"cube","uuid":"741187ae-e05b-4c69-1555-99303f3e9f04"}],"outliner":[{"name":"root","origin":[0,0,0],"color":0,"uuid":"ee7748d0-5b3e-59a3-7df5-d010791b2142","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["023a3320-18c3-d968-3a13-56914da8e6f0",{"name":"bag","origin":[0,-9,0],"color":0,"uuid":"ca7f77db-f514-0ae5-d753-742da3da9103","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["1ca3a675-33f5-744f-58f9-cf14867dcfb1","90ba7ded-8e83-43de-e4da-bb237f43bdd7","741187ae-e05b-4c69-1555-99303f3e9f04","5cc3052b-c843-eec8-9326-2bfd1b1fd435","9a732bc0-bf4d-cc97-85fb-674e15c88c5c"]}]}],"textures":[{"path":"/home/sollace/Documents/GitRepos/minecraft_mods/Unicopia/assets/models/hanging_sandbag.png","name":"hanging_sandbag.png","folder":"block","namespace":"","id":"0","width":32,"height":32,"uv_width":32,"uv_height":32,"particle":false,"layers_enabled":false,"sync_to_project":"","render_mode":"default","render_sides":"auto","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"internal":true,"saved":true,"uuid":"b9376c08-3fa3-5dae-fbe1-2efee48a6e4b","relative_path":"../hanging_sandbag.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABEJJREFUWEftlktPW0cUx//GMTUYCLYxvn6AX7HBOA0hYAPqolLbtKqiqKpYRF100U9QqZGqLKp+gKpdpNu2yrqVomwatYryUFoEBuM6DY/EUBPbubavL2CDH4QEbFczrl3bwb4hKekms7l37plzzm/O/GfmilCnLd7zFYiJZVno9fryqMQmB5PRVuUV41g4h94U1YvV6Htdp1g8VJAc/TcxCbK7xSKX38NXF69Uxfz80w+h11heDsCsZxo3JtnDByBLoDadqEoUWpoFGw1BqTLjpyu/lW2HUoH9AOotwcfnnP+9BgiAQqFAMBiC0WhAIpGgM97eSdFnNBKDVqcpV+G5RXh76ipV++5jQNbajie5NLgYTwObLUZsJbehYbTYfryJaISDvFOOXkMPNtYy6FYrsBpcxmYyBWlzG6SyJnTJtXTnkHcS59zEJw3FKfrx8qXC2LgLybUsVIwCTU0AG45DLD4CZXcbTaTvYSA5IoXvjhe53BOYzRbw8TVIX5NBoWpDJMwhmebRbzsOlVIDr8+Dk4OnMDVzE2dOf9QYwPuHu6DtUeHBagjHrBY6kznvDFpbZLDbB7Cy4ofV2ofNNI8VfxBSqRSOgeO471+E1WpFLp9DlI2D53n0O8xYDYQh71CivbMFyY0MRk6NNwa4futqweUcw+LSn3AMDCKZ4rDOpdEkFoHRdiEcjsBkMiCX20Mssk6XRt/LgH3I0co0S1qxsHAX2cw2XC4XUtl1CjE85ML09BTeO31WGMBqNVNatVYBWUsnZj1uNDeL0W+3I/KQg+6fJZif90EslsAx8Dr8K/fRb7NTUd69s0TBSAU6ZF2YX/JBp9U9WwWoBkbfoAEy6Sw6jrZR8YhEIsiV7VjnE+jrsyOd2QIf36Dj1BoleC6BRzuZIoz/HoLhVbzz1vuYm/PQMSMjTly/+YuwCEu7gDiRxIymmwYgyh4cPIFUegsRNkq/6fRaqhXyvbKRMZO/u6FUyjHqGqemmdlp+hTcBVWRAPy8EKLbstTUu0FomOKd8CKXTm2eUv8pgRCAsWPFhO6/WMjTATRLxWX/2gOHVLCyct9+d6sq1+VLXzcW4X4VqAQ4qdyjMy+1egDErlHrcPGHa9CpGTo8EufwXAC1S1DZ3w+A2EV5CXoNvTj/5fcHA2BjgYLX68HwsJPOlKx3KBiCwWgoCo8x49FOmr63SNsx6f61qmj5Qr6cnBgIQGV7pgosL/sLNltfea08vtuFepcLuaQq/5JMRgsCgQAsFgvN+yAYoHcBaZV/UiUfh32oShO0QwDIk0CUkk9MfDB64YvP3Bc0c1UzusGcf0pUocQ16m9QvHvgv6J9HQgECUiq8Db3TWFMXTwb3HEetQCl5CXKg0IIEgsBZHfZqnNDJtELxqwsqeBgAlDp8NIrUHtO1PYPvQJCAIeuASGAVxV4VQEhjQjZBc8BoQAvav/fAf4GYEkKP0m+kyEAAAAASUVORK5CYII="}],"fabricOptions":{"header":"package com.example.mod;","entity":"Entity","render":"","members":""}} \ No newline at end of file diff --git a/assets/models/hanging_sandbag.java b/assets/models/hanging_sandbag.java new file mode 100644 index 00000000..00cf4263 --- /dev/null +++ b/assets/models/hanging_sandbag.java @@ -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 { + 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); + } +} \ No newline at end of file diff --git a/assets/models/hanging_sandbag.png b/assets/models/hanging_sandbag.png new file mode 100644 index 00000000..fdee304f Binary files /dev/null and b/assets/models/hanging_sandbag.png differ diff --git a/assets/models/hay_bale.json b/assets/models/hay_bale.json deleted file mode 100644 index a2ce1538..00000000 --- a/assets/models/hay_bale.json +++ /dev/null @@ -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"} - } - } - ] -} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityModel.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityModel.java index 03c14bf9..1a543310 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityModel.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityModel.java @@ -4,6 +4,7 @@ import java.util.List; import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.model.*; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.entity.model.EntityModel; @@ -14,26 +15,37 @@ import net.minecraft.util.math.MathHelper; public class AirBalloonEntityModel extends EntityModel { private final ModelPart root; + private ModelPart main; private float inflation; private boolean isBurner; private boolean isBalloon; + private boolean isSandbags; private final List ropes; + private final List sandbags; public AirBalloonEntityModel(ModelPart root) { this.root = root; isBurner = root.hasChild("burner"); + isSandbags = root.hasChild("sandbag_ne"); isBalloon = root.hasChild("canopy"); if (isBurner || isBalloon) { - ModelPart part = root.getChild(isBalloon ? "canopy" : "burner"); - ropes = List.of(part.getChild("rope_a"), part.getChild("rope_b"), part.getChild("rope_c"), - part.getChild("rope_d")); + main = root.getChild(isBalloon ? "canopy" : "burner"); + ropes = List.of( + (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 { 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() { @@ -56,12 +68,34 @@ public class AirBalloonEntityModel extends EntityModel { public static TexturedModelData getBurnerModelData() { ModelData modelData = new ModelData(); 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)); - 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)); - 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)); - 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)); - 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)); + root.addChild("strut_a", ModelPartBuilder.create() + .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) + + .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); } @@ -76,14 +110,40 @@ public class AirBalloonEntityModel extends EntityModel { 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 - public void setAngles(AirBalloonEntity entity, float tickDelta, float limbSwingAmount, float ageInTicks, - float netHeadYaw, float headPitch) { + public void setAngles(AirBalloonEntity entity, float limbDistance, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + float tickDelta = MinecraftClient.getInstance().getTickDelta(); inflation = entity.getInflation(tickDelta); - if (isBurner || isBalloon) { - 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); + root.yaw = MathHelper.PI; + + 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()) { root.roll *= -1; root.pitch *= -1; @@ -93,27 +153,44 @@ public class AirBalloonEntityModel extends EntityModel { root.roll = 0; } - for (ModelPart rope : ropes) { - rope.resetTransform(); - } + ropes.forEach(ModelPart::resetTransform); if (isBurner) { 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; ropes.forEach(rope -> { 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) { - root.pivotY = 0; + if (isBalloon || isSandbags) { + root.pivotY = burnerWiggleProgress * 3; root.pivotX = inflation * MathHelper.cos(limbSwingAmount + entity.age / 5F) / 4F; if (entity.getBasketType().isOf(BoatEntity.Type.BAMBOO)) { 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 { if (i == 0 || i == 1) { 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; + } } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java index 5466f5f4..ad31e128 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/AirBalloonEntityRenderer.java @@ -1,9 +1,11 @@ package com.minelittlepony.unicopia.client.render.entity; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.entity.collision.MultiBox; import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity; import net.minecraft.client.MinecraftClient; @@ -17,15 +19,22 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.item.Items; import net.minecraft.util.Hand; import net.minecraft.util.Identifier; -import net.minecraft.util.math.Box; public class AirBalloonEntityRenderer extends MobEntityRenderer { public AirBalloonEntityRenderer(EntityRendererFactory.Context context) { 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"); - })); - addFeature(new BalloonFeature(new AirBalloonEntityModel(AirBalloonEntityModel.getCanopyModelData().createModel()), this, AirBalloonEntity::hasBalloon, e -> getComponentTexture("canopy/" + e.getDesign().asString()))); + }, (light, entity) -> entity.isAscending() ? 0xFF00FF : light)); + 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 @@ -33,9 +42,9 @@ public class AirBalloonEntityRenderer extends MobEntityRenderer { + 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 visibilityTest; private final Function textureFunc; + private final BiFunction lightFunc; public BalloonFeature(AirBalloonEntityModel model, FeatureRendererContext context, Predicate visibilityTest, - Function textureFunc) { + Function textureFunc, + BiFunction lightFunc) { super(context); this.model = model; this.visibilityTest = visibilityTest; this.textureFunc = textureFunc; + this.lightFunc = lightFunc; } @Override public void render(MatrixStack matrices, VertexConsumerProvider vertices, int light, AirBalloonEntity entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float yaw, float pitch) { 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); } } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Transportation.java b/src/main/java/com/minelittlepony/unicopia/entity/Transportation.java index 14ad5346..34632a16 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Transportation.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Transportation.java @@ -14,6 +14,7 @@ import net.minecraft.block.ShapeContext; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.MovementType; +import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.util.math.Box; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -124,6 +125,9 @@ public class Transportation implements Tickable { @Nullable private Box getVehicleBox() { + if (!EntityPredicates.EXCEPT_SPECTATOR.test(living.asEntity())) { + return null; + } if (vehicle == null) { return null; } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/collision/MultiBox.java b/src/main/java/com/minelittlepony/unicopia/entity/collision/MultiBox.java index 921cafbe..e39b6ffc 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/collision/MultiBox.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/collision/MultiBox.java @@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.entity.collision; import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -24,6 +25,12 @@ public final class MultiBox extends Box { return box instanceof MultiBox m ? m.first : box; } + public static void forEach(Box box, Consumer consumer) { + if (box instanceof MultiBox m) { + m.children.forEach(consumer); + } + } + private MultiBox(Box first, BoxChildren children) { super(first.minX, first.minY, first.minZ, first.maxX, first.maxY, first.maxZ); this.first = unbox(first); @@ -148,6 +155,12 @@ public final class MultiBox extends Box { return false; } + public void forEach(Consumer consumer) { + for (int i = 0; i < children.length; i++) { + consumer.accept(children[i]); + } + } + @Override public String toString() { return toString.get(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/mob/AirBalloonEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/mob/AirBalloonEntity.java index 690c1a6b..b9d5943d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/mob/AirBalloonEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/mob/AirBalloonEntity.java @@ -39,10 +39,10 @@ import java.util.function.Function; import java.util.function.IntFunction; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; - import com.minelittlepony.unicopia.EquineContext; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.USounds; @@ -65,6 +65,8 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp private static final TrackedData BASKET_TYPE = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.STRING); private static final TrackedData BALLOON_DESIGN = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER); + public static final byte STATUS_BURNER_INTERACT = (byte)105; + private static final Predicate RIDER_PREDICATE = EntityPredicates.EXCEPT_SPECTATOR.and(e -> { return !(e instanceof PlayerEntity p && p.getAbilities().flying); }); @@ -73,9 +75,17 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp private int prevInflation; private Vec3d manualVelocity = Vec3d.ZERO; - private int maxFuel = 100; + private int maxFuel = 10000; 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 type, World world) { super(type, world); intersectionChecked = true; @@ -108,12 +118,20 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp 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() { return getDesign() != BalloonDesign.NONE; } public boolean hasBurner() { - return !getStackInHand(Hand.MAIN_HAND).isEmpty(); + return getHandItems() != null && !getStackInHand(Hand.MAIN_HAND).isEmpty(); } public float getInflation(float tickDelta) { @@ -152,6 +170,14 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp 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 public void tick() { setAir(getMaxAir()); @@ -179,8 +205,8 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp setInflation(inflation); } - if (fuel > -6 && age % 60 == 0) { - fuel -= boosting ? 10 : 1; + if (fuel > -6 && age % 2 == 0) { + fuel -= boosting ? 50 : 1; if (fuel <= -6) { setBoostTicks(0); setAscending(false); @@ -262,15 +288,26 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp setFireTicks(1); } + for (Animatable bag : sandbags) { + bag.tick(); + } + burner.tick(); + super.tick(); + + prevXDelta = xDelta; + prevZDelta = zDelta; + xDelta = getX() - prevX; + zDelta = getZ() - prevZ; } @Override public ActionResult interactAt(PlayerEntity player, Vec3d hitPos, Hand 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)) { setAscending(!isAscending()); if (isAscending()) { @@ -281,31 +318,45 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp if (!player.isSneaky()) { getWorld().emitGameEvent(player, GameEvent.ENTITY_INTERACT, getBlockPos()); } - return ActionResult.SUCCESS; - } - - 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()); - } + burner.setPulling(); return ActionResult.SUCCESS; } if (stack.isEmpty() && isAscending()) { setBoostTicks(50); playSound(USounds.ENTITY_HOT_AIR_BALLOON_BOOST, 1, 1); + burner.setPulling(); if (!player.isSneaky()) { getWorld().emitGameEvent(player, GameEvent.ENTITY_INTERACT, getBlockPos()); } 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; @@ -368,6 +419,7 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp if (!player.getAbilities().creativeMode) { stack.decrement(1); } + burner.setPulling(); playSound(USounds.Vanilla.ENTITY_VILLAGER_YES, 1, 1); return ActionResult.SUCCESS; } @@ -486,7 +538,26 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp @Override protected Box calculateBoundingBox() { - return MultiBox.of(super.calculateBoundingBox(), getBoundingBoxes()); + List 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 @@ -509,6 +580,14 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp .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 public List getGravityZoneBoxes() { Box balloon = getBalloonBoundingBox().expand(0.001); @@ -528,29 +607,55 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp public List getBoundingBoxes() { List boxes = new ArrayList<>(); Box box = getInteriorBoundingBox(); + Box mainBox = MultiBox.unbox(getBoundingBox()); + boxes.add(box); double wallheight = box.maxY + 0.72; - double wallThickness = 0.2; + double wallThickness = 0.3; + double halfDoorWidth = 0.5; if (!getBasketType().isOf(BoatEntity.Type.BAMBOO)) { + // 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) - 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 - 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 - 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 - 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) { - boxes.add(getBalloonBoundingBox()); + if (hasBalloon() && getInflation(1) >= 1) { + 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; } @@ -574,6 +679,10 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp } private void movePassenger(Entity passenger, Vec3d movement) { + if (!EntityPredicates.EXCEPT_SPECTATOR.test(passenger)) { + return; + } + Living living = Living.living(passenger); if (living != null) { if (living.getPhysics().isGravityNegative()) { @@ -625,10 +734,54 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp 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) { 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") public enum BalloonDesign implements StringIdentifiable { NONE, diff --git a/src/main/java/com/minelittlepony/unicopia/item/BasketItem.java b/src/main/java/com/minelittlepony/unicopia/item/BasketItem.java index beb93ee4..9e7a8e86 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/BasketItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/BasketItem.java @@ -68,7 +68,7 @@ public class BasketItem extends Item implements Dispensable { } 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); @@ -76,9 +76,11 @@ public class BasketItem extends Item implements Dispensable { private TypedActionResult placeEntity(ItemStack stack, World world, double x, double y, double z, float yaw, @Nullable PlayerEntity user) { 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.setBodyYaw(yaw); + entity.setYaw(yaw); entity.setBasketType(type); if (!world.isSpaceEmpty(entity, entity.getBoundingBox())) { return TypedActionResult.fail(stack); @@ -92,7 +94,6 @@ public class BasketItem extends Item implements Dispensable { stack.decrement(1); } } - return TypedActionResult.success(stack, world.isClient()); } } \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/dawn.png b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/dawn.png index 0a17fef9..64d8bf42 100644 Binary files a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/dawn.png and b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/dawn.png differ diff --git a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/equality.png b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/equality.png index c87606b9..6f7e62be 100644 Binary files a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/equality.png and b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/equality.png differ diff --git a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/luna.png b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/luna.png index 526d6d66..d94ae769 100644 Binary files a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/luna.png and b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/luna.png differ diff --git a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/storm.png b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/storm.png index 65f049a5..49d2cee3 100644 Binary files a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/storm.png and b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/storm.png differ diff --git a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/tale.png b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/tale.png index 6f074e82..39e2f703 100644 Binary files a/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/tale.png and b/src/main/resources/assets/unicopia/textures/entity/air_balloon/canopy/tale.png differ diff --git a/src/main/resources/assets/unicopia/textures/entity/air_balloon/sandbags.png b/src/main/resources/assets/unicopia/textures/entity/air_balloon/sandbags.png new file mode 100644 index 00000000..fdee304f Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/entity/air_balloon/sandbags.png differ