diff --git a/assets/models/sombra.bbmodel b/assets/models/sombra.bbmodel new file mode 100644 index 00000000..f0884723 --- /dev/null +++ b/assets/models/sombra.bbmodel @@ -0,0 +1 @@ +{"meta":{"format_version":"4.5","model_format":"modded_entity","box_uv":true},"name":"sombramodel","model_identifier":"unicopia:sombra","modded_entity_version":"Fabric 1.17+","modded_entity_flip_y":true,"visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"unhandled_root_fields":{},"resolution":{"width":64,"height":64},"elements":[{"name":"head","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-3,9,-4],"to":[5,17,4],"autouv":0,"color":1,"origin":[3,9,0],"faces":{"north":{"uv":[8,8,16,16],"texture":0},"east":{"uv":[0,8,8,16],"texture":0},"south":{"uv":[24,8,32,16],"texture":0},"west":{"uv":[16,8,24,16],"texture":0},"up":{"uv":[16,8,8,0],"texture":0},"down":{"uv":[24,0,16,8],"texture":0}},"type":"cube","uuid":"bc7464a6-08da-2c3d-b824-806afc60ec2f"},{"name":"left_ear","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-3,17,-4],"to":[-1,19,-2],"autouv":0,"color":7,"origin":[3,9,0],"uv_offset":[0,4],"faces":{"north":{"uv":[2,6,4,8],"texture":0},"east":{"uv":[0,6,2,8],"texture":0},"south":{"uv":[6,6,8,8],"texture":0},"west":{"uv":[4,6,6,8],"texture":0},"up":{"uv":[4,6,2,4],"texture":0},"down":{"uv":[6,4,4,6],"texture":0}},"type":"cube","uuid":"3c3ff2ce-9249-de7f-730b-8ee766c695b6"},{"name":"right_ear","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-3,17,2],"to":[-1,19,4],"autouv":0,"color":7,"origin":[3,9,0],"uv_offset":[0,4],"faces":{"north":{"uv":[2,6,4,8],"texture":0},"east":{"uv":[0,6,2,8],"texture":0},"south":{"uv":[6,6,8,8],"texture":0},"west":{"uv":[4,6,6,8],"texture":0},"up":{"uv":[4,6,2,4],"texture":0},"down":{"uv":[6,4,4,6],"texture":0}},"type":"cube","uuid":"fe04ee6c-24f0-f61c-7fb1-72edf3f916b2"},{"name":"neck","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-6.043807145043602,2.9667667014561756,-3],"to":[-2.043807145043603,9.966766701456175,2],"autouv":0,"color":0,"rotation":[0,0,-40],"origin":[0,4,0],"uv_offset":[32,10],"faces":{"north":{"uv":[37,15,41,22],"texture":0},"east":{"uv":[32,15,37,22],"texture":0},"south":{"uv":[46,15,50,22],"texture":0},"west":{"uv":[41,15,46,22],"texture":0},"up":{"uv":[41,15,37,10],"texture":0},"down":{"uv":[45,10,41,15],"texture":0}},"type":"cube","uuid":"5a49ec12-4d4a-792e-60cc-5b071971b658"},{"name":"tail","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-10.095760221444959,-2.1321178182447698,-2],"to":[-7.0957602214449595,4.86788218175523,1],"autouv":0,"color":0,"rotation":[0,0,-57.5],"origin":[-4,1,-1],"uv_offset":[50,12],"faces":{"north":{"uv":[53,15,56,22],"texture":0},"east":{"uv":[50,15,53,22],"texture":0},"south":{"uv":[59,15,62,22],"texture":0},"west":{"uv":[56,15,59,22],"texture":0},"up":{"uv":[56,15,53,12],"texture":0},"down":{"uv":[59,12,56,15],"texture":0}},"type":"cube","uuid":"170393c0-9f4d-1e2d-9f6b-4aff0e8252ff"},{"name":"upper_jaw","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[3,9,-3],"to":[9,11,3],"autouv":0,"color":0,"rotation":[0,0,-10],"origin":[4,9,0],"uv_offset":[32,30],"faces":{"north":{"uv":[38,36,44,38],"texture":0},"east":{"uv":[32,36,38,38],"texture":0},"south":{"uv":[50,36,56,38],"texture":0},"west":{"uv":[44,36,50,38],"texture":0},"up":{"uv":[44,36,38,30],"texture":0},"down":{"uv":[50,30,44,36],"texture":0}},"type":"cube","uuid":"91ed1e39-37ba-0b0b-66a4-d6faa039747a"},{"name":"lower_jaw","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-1,5,-3],"to":[6,7,3],"autouv":0,"color":0,"rotation":[0,0,-32.5],"origin":[1,7,0],"uv_offset":[32,22],"faces":{"north":{"uv":[38,28,45,30],"texture":0},"east":{"uv":[32,28,38,30],"texture":0},"south":{"uv":[51,28,58,30],"texture":0},"west":{"uv":[45,28,51,30],"texture":0},"up":{"uv":[45,28,38,22],"texture":0},"down":{"uv":[52,22,45,28],"texture":0}},"type":"cube","uuid":"96926946-d0c4-8fdc-8147-abaeb16c47de"},{"name":"base_ring","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-2,17.75,-4],"to":[6,20.75,4],"autouv":0,"color":1,"inflate":0.5,"origin":[4,12.75,0],"uv_offset":[0,16],"faces":{"north":{"uv":[8,24,16,27],"texture":0},"east":{"uv":[0,24,8,27],"texture":0},"south":{"uv":[24,24,32,27],"texture":0},"west":{"uv":[16,24,24,27],"texture":0},"up":{"uv":[16,24,8,16],"texture":0},"down":{"uv":[24,16,16,24],"texture":0}},"type":"cube","uuid":"8e97c445-9323-0963-8dba-6c2a0c06f822"},{"name":"horn_base","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-0.21393804843269637,13.830222215594894,-0.5],"to":[0.7860619515673033,16.830222215594894,0.5],"autouv":0,"color":0,"inflate":0.1,"origin":[3,10,0.5],"faces":{"north":{"uv":[1,1,1.9999999999999996,4],"texture":0},"east":{"uv":[0,1,1,4],"texture":0},"south":{"uv":[2.9999999999999996,1,3.999999999999999,4],"texture":0},"west":{"uv":[1.9999999999999996,1,2.9999999999999996,4],"texture":0},"up":{"uv":[1.9999999999999996,1,0.9999999999999999,0],"texture":0},"down":{"uv":[2.999999999999999,0,1.9999999999999996,1],"texture":0}},"type":"cube","uuid":"5b8a2bcf-dfa8-c404-c10c-cf5bf3f57e97"},{"name":"horn_middle","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[0.5,17.33012701892219,-0.5],"to":[1.5,19.330127018922187,0.5],"autouv":0,"color":0,"origin":[3.9999999999999982,13,0],"uv_offset":[4,0],"faces":{"north":{"uv":[5,1,6,2.9999999999999964],"texture":0},"east":{"uv":[4,1,5,2.9999999999999964],"texture":0},"south":{"uv":[7,1,8,2.9999999999999964],"texture":0},"west":{"uv":[6,1,7,2.9999999999999964],"texture":0},"up":{"uv":[6,1,5,0],"texture":0},"down":{"uv":[7,0,6,1],"texture":0}},"type":"cube","uuid":"71f15e09-b8ee-6464-77f4-fa8594401237"},{"name":"horn_tip","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[1.4964710024786338,19.768584753741134,-0.5],"to":[2.496471002478634,21.768584753741134,0.5],"autouv":0,"color":0,"inflate":-0.1,"rotation":[0,0,12.5],"origin":[3.9999999999999982,15,0],"uv_offset":[4,0],"faces":{"north":{"uv":[5,1,6,3],"texture":0},"east":{"uv":[4,1,5,3],"texture":0},"south":{"uv":[7,1,8,3],"texture":0},"west":{"uv":[6,1,7,3],"texture":0},"up":{"uv":[6,1,5,0],"texture":0},"down":{"uv":[7,0,6,1],"texture":0}},"type":"cube","uuid":"7c25087d-51ea-9f8f-e290-93eaa9f343d9"},{"name":"mane","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-4.5017649934731185,15.1227811127697,-1.5],"to":[3.4982350065268815,22.1227811127697,1.5],"autouv":0,"color":0,"rotation":[0,0,27.5],"origin":[1,16,0],"uv_offset":[32,0],"faces":{"north":{"uv":[35,3,43,10.000000000000002],"texture":0},"east":{"uv":[32,3,35,10.000000000000002],"texture":0},"south":{"uv":[46,3,54,10.000000000000002],"texture":0},"west":{"uv":[43,3,46,10.000000000000002],"texture":0},"up":{"uv":[43,3,35,0],"texture":0},"down":{"uv":[51,0,43,3],"texture":0}},"type":"cube","uuid":"827dfa62-7b3a-5ba9-ac93-45e4b3468c2a"},{"name":"hair","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[-3,10.75,-4],"to":[5,19.75,4],"autouv":0,"color":1,"inflate":0.25,"rotation":[0,0,2.5],"origin":[3,11.75,0],"uv_offset":[0,16],"faces":{"north":{"uv":[8,24,16,33],"texture":0},"east":{"uv":[0,24,8,33],"texture":0},"south":{"uv":[24,24,32,33],"texture":0},"west":{"uv":[16,24,24,33],"texture":0},"up":{"uv":[16,24,8,16],"texture":0},"down":{"uv":[24,16,16,24],"texture":0}},"type":"cube","uuid":"91f86823-a949-1a50-c9e3-15af7453902a"},{"name":"gem","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[6,17.75,-0.75],"to":[7,18.75,0.25],"autouv":1,"color":0,"origin":[6,17.75,0.25],"uv_offset":[1,1],"faces":{"north":{"uv":[2,2,3,3],"texture":0},"east":{"uv":[1,2,2,3],"texture":0},"south":{"uv":[4,2,5,3],"texture":0},"west":{"uv":[3,2,4,3],"texture":0},"up":{"uv":[3,2,2,1],"texture":0},"down":{"uv":[4,1,3,2],"texture":0}},"type":"cube","uuid":"3ef66abf-4260-e837-8aed-d968b7b40676"},{"name":"spike_r1","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[1,17.75,4.25],"to":[2,21.75,4.25],"autouv":0,"color":0,"rotation":[30,0,0],"origin":[1,17.75,4.25],"uv_offset":[2,20],"faces":{"north":{"uv":[2,20,3,24],"texture":0},"east":{"uv":[2,20,2,24],"texture":0},"south":{"uv":[3,20,4,24],"texture":0},"west":{"uv":[3,20,3,24],"texture":0},"up":{"uv":[3,20,2,20],"texture":0},"down":{"uv":[4,20,3,20],"texture":0}},"type":"cube","uuid":"d9be8fd6-42ce-e48d-ba3b-fe2dd9db8f9f"},{"name":"spike_r2","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[4,17.75,4.25],"to":[5,21.75,4.25],"autouv":0,"color":0,"rotation":[29.14742626402818,7.435472226131844,-13.064313429508289],"origin":[4,17.75,4.25],"uv_offset":[2,20],"faces":{"north":{"uv":[2,20,3,24],"texture":0},"east":{"uv":[2,20,2,24],"texture":0},"south":{"uv":[3,20,4,24],"texture":0},"west":{"uv":[3,20,3,24],"texture":0},"up":{"uv":[3,20,2,20],"texture":0},"down":{"uv":[4,20,3,20],"texture":0}},"type":"cube","uuid":"e89ae315-2008-46ed-84ce-046bf701a08c"},{"name":"spike_l2","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[1,17.75,-4.25],"to":[2,21.75,-4.25],"autouv":0,"color":0,"rotation":[-30,0,0],"origin":[1,17.75,-4.25],"uv_offset":[2,20],"faces":{"north":{"uv":[2,20,3,24],"texture":0},"east":{"uv":[2,20,2,24],"texture":0},"south":{"uv":[3,20,4,24],"texture":0},"west":{"uv":[3,20,3,24],"texture":0},"up":{"uv":[3,20,2,20],"texture":0},"down":{"uv":[4,20,3,20],"texture":0}},"type":"cube","uuid":"61c8db47-1f05-ee0a-2176-fd6ce04fd10a"},{"name":"spike_l1","box_uv":true,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[4,17.75,-4.25],"to":[5,21.75,-4.25],"autouv":0,"color":0,"rotation":[-29.147399999999834,7.435472226131878,-13.064313429508289],"origin":[4,17.75,-4.25],"uv_offset":[2,20],"faces":{"north":{"uv":[2,20,3,24],"texture":0},"east":{"uv":[2,20,2,24],"texture":0},"south":{"uv":[3,20,4,24],"texture":0},"west":{"uv":[3,20,3,24],"texture":0},"up":{"uv":[3,20,2,20],"texture":0},"down":{"uv":[4,20,3,20],"texture":0}},"type":"cube","uuid":"363ce552-e389-d0fa-03e2-ddee71a12a55"}],"outliner":[{"name":"neck","origin":[0,4,0],"rotation":[0,0,2.5],"color":0,"uuid":"b6d70cd6-79b5-6e4f-ac50-d4a117f91948","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["5a49ec12-4d4a-792e-60cc-5b071971b658","170393c0-9f4d-1e2d-9f6b-4aff0e8252ff"]},{"name":"head","origin":[0,4,0],"color":0,"uuid":"e1ebdfca-cb37-98a4-5e05-70b24d644a68","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["bc7464a6-08da-2c3d-b824-806afc60ec2f",{"name":"crown","origin":[4,12.75,0],"rotation":[0,0,7.5],"color":0,"uuid":"bc02d715-c329-5a53-9c8f-a50e43451fc9","export":true,"mirror_uv":false,"isOpen":false,"locked":false,"visibility":true,"autouv":0,"children":["8e97c445-9323-0963-8dba-6c2a0c06f822","3ef66abf-4260-e837-8aed-d968b7b40676","d9be8fd6-42ce-e48d-ba3b-fe2dd9db8f9f","363ce552-e389-d0fa-03e2-ddee71a12a55","61c8db47-1f05-ee0a-2176-fd6ce04fd10a","e89ae315-2008-46ed-84ce-046bf701a08c"]},"91f86823-a949-1a50-c9e3-15af7453902a","3c3ff2ce-9249-de7f-730b-8ee766c695b6","fe04ee6c-24f0-f61c-7fb1-72edf3f916b2","91ed1e39-37ba-0b0b-66a4-d6faa039747a","96926946-d0c4-8fdc-8147-abaeb16c47de",{"name":"horn","origin":[3,10,0.5],"rotation":[0,0,-47.5],"color":0,"uuid":"f2c6a540-30a4-15d2-414c-5da030dac8c2","export":true,"mirror_uv":false,"isOpen":false,"locked":false,"visibility":true,"autouv":0,"children":["5b8a2bcf-dfa8-c404-c10c-cf5bf3f57e97",{"name":"bone","origin":[3.9999999999999982,13,0],"rotation":[0,0,10],"color":0,"uuid":"6682c5f6-4457-0e19-45b2-8dd59ad45fab","export":true,"mirror_uv":false,"isOpen":true,"locked":false,"visibility":true,"autouv":0,"children":["7c25087d-51ea-9f8f-e290-93eaa9f343d9","71f15e09-b8ee-6464-77f4-fa8594401237"]}]},"827dfa62-7b3a-5ba9-ac93-45e4b3468c2a"]}],"textures":[{"path":"/home/sollace/Documents/GitRepos/minecraft_mods/Unicopia/assets/models/sombra.png","name":"sombra.png","folder":"block","namespace":"","id":"0","particle":false,"render_mode":"default","render_sides":"auto","frame_time":1,"frame_order_type":"loop","frame_order":"","frame_interpolate":false,"visible":true,"mode":"bitmap","saved":true,"uuid":"54cea3c2-1c40-0368-b88a-7ec1082c59f8","relative_path":"../sombra.png","source":"data:image/png;base64,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"}],"fabricOptions":{"header":"package com.example.mod;","entity":"Entity","render":"","members":""}} \ No newline at end of file diff --git a/assets/models/sombra.png b/assets/models/sombra.png new file mode 100644 index 00000000..55774f8e Binary files /dev/null and b/assets/models/sombra.png differ diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index dbfc4433..32cc4c41 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -78,6 +78,7 @@ public interface URenderers { EntityRendererRegistry.register(UEntities.CAST_SPELL, CastSpellEntityRenderer::new); EntityRendererRegistry.register(UEntities.TWITTERMITE, FairyEntityRenderer::new); EntityRendererRegistry.register(UEntities.SPELLBOOK, SpellbookEntityRenderer::new); + EntityRendererRegistry.register(UEntities.SOMBRA, SombraEntityRenderer::new); EntityRendererRegistry.register(UEntities.AIR_BALLOON, AirBalloonEntityRenderer::new); BlockEntityRendererFactories.register(UBlockEntities.WEATHER_VANE, WeatherVaneBlockEntityRenderer::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/SombraEntityModel.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SombraEntityModel.java new file mode 100644 index 00000000..9ad47e42 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SombraEntityModel.java @@ -0,0 +1,114 @@ +package com.minelittlepony.unicopia.client.render.entity; + +import com.minelittlepony.unicopia.entity.SombraEntity; + +import net.minecraft.client.model.ModelData; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.model.ModelPartBuilder; +import net.minecraft.client.model.ModelPartData; +import net.minecraft.client.model.ModelTransform; +import net.minecraft.client.model.Dilation; +import net.minecraft.client.model.TexturedModelData; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.MathHelper; + +public class SombraEntityModel extends EntityModel { + + private final ModelPart part; + + private final ModelPart head; + private final ModelPart mane; + private final ModelPart upperJaw; + private final ModelPart lowerJaw; + + private final ModelPart body; + + public SombraEntityModel(ModelPart root) { + this.part = root; + this.head = root.getChild("head"); + this.mane = head.getChild("mane"); + this.upperJaw = head.getChild("upper_jaw"); + this.lowerJaw = head.getChild("lower_jaw"); + this.body = root.getChild("body"); + } + + public static TexturedModelData getTexturedModelData() { + ModelData data = new ModelData(); + ModelPartData root = data.getRoot(); + + ModelPartData neck = root.addChild("body", ModelPartBuilder.create(), ModelTransform.of(0, 20, 0, 0, 0, 0.0436F)); + neck.addChild("tail", ModelPartBuilder.create() + .uv(50, 12).cuboid(3.0958F, -3.8679F, -1, 3, 7, 3, Dilation.NONE), ModelTransform.of(4, 3, -1, 0, 0, -1.0036F)); + neck.addChild("neck", ModelPartBuilder.create() + .uv(32, 10).cuboid(2.0438F, -5.9668F, -3, 4, 7, 5, Dilation.NONE), ModelTransform.of(0, 0, 0, 0, 0, -0.6981F)); + + ModelPartData head = root.addChild("head", ModelPartBuilder.create() + .uv(0, 0).cuboid(-5, -13, -4, 8, 8, 8, Dilation.NONE) // head + .uv(0, 4).cuboid(1, -15, -4, 2, 2, 2, Dilation.NONE) // ear + .uv(0, 4).cuboid(1, -15, 2, 2, 2, 2, Dilation.NONE) // ear + , ModelTransform.pivot(0, 20, 0)); + + head.addChild("mane", ModelPartBuilder.create() + .uv(32, 0).cuboid(-2.4982F, -6.1228F, -1.5F, 8, 7, 3, Dilation.NONE), ModelTransform.of(-1, -12, 0, 0, 0, 0.48F)); + + head.addChild("lower_jaw", ModelPartBuilder.create() + .uv(32, 22).cuboid(-5, 0, -3, 7, 2, 6, Dilation.NONE), ModelTransform.of(-1, -3, 0, 0, 0, -0.5672F)); + head.addChild("upper_jaw", ModelPartBuilder.create() + .uv(32, 30).cuboid(-5, -2, -3, 6, 2, 6, Dilation.NONE), ModelTransform.of(-4, -5, 0, 0, 0, -0.1745F)); + head.addChild("hair", ModelPartBuilder.create() + .uv(0, 16).cuboid(-2, -8, -4, 8, 9, 8, new Dilation(0.25F)), ModelTransform.of(-3, -7.75F, 0, 0, 0, 0.0436F)); + + ModelPartData crown = head.addChild("crown", ModelPartBuilder.create() + .uv(0, 16).cuboid(-2, -8, -4, 8, 3, 8, new Dilation(0.5F)) + .uv(1, 1).cuboid(-3, -6, -0.75F, 1, 1, 1, Dilation.NONE), ModelTransform.of(-4, -8.75F, 0, 0, 0, 0.1309F)); + + crown.addChild("spike_r2", ModelPartBuilder.create() + .uv(2, 20).cuboid(-1, -4, 0, 1, 4, 0, Dilation.NONE), ModelTransform.of(0, -5, 4.25F, -0.5087F, -0.1298F, -0.228F)); + crown.addChild("spike_l2", ModelPartBuilder.create() + .uv(2, 20).cuboid(-1, -4, 0, 1, 4, 0, Dilation.NONE), ModelTransform.of(3, -5, -4.25F, 0.5236F, 0, 0)); + crown.addChild("spike_l1", ModelPartBuilder.create() + .uv(2, 20).cuboid(-1, -4, 0, 1, 4, 0, Dilation.NONE), ModelTransform.of(0, -5, -4.25F, 0.5087F, -0.1298F, -0.228F)); + crown.addChild("spike_r1", ModelPartBuilder.create() + .uv(2, 20).cuboid(-1, -4, 0, 1, 4, 0, Dilation.NONE), ModelTransform.of(3, -5, 4.25F, -0.5236F, 0, 0)); + + head.addChild("horn", ModelPartBuilder.create() + .uv(0, 0).cuboid(2.2139F, -6.8302F, -1, 1, 3, 1, new Dilation(0.1F)), ModelTransform.of(-3, -6, 0.5F, 0, 0, -0.829F)) + .addChild("bone", ModelPartBuilder.create() + .uv(4, 0).cuboid(2.5F, -6.3301F, -0.5F, 1, 2, 1, Dilation.NONE), ModelTransform.of(-1, -3, -0.5F, 0, 0, 0.1745F)) + .addChild("horn_tip", ModelPartBuilder.create() + .uv(4, 0).cuboid(1.5035F, -6.7686F, -0.5F, 1, 2, 1, new Dilation(-0.1F)), ModelTransform.of(0, -2, 0, 0, 0, 0.2182F)); + + return TexturedModelData.of(data, 64, 64); + } + + @Override + public void setAngles(SombraEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + + part.yaw = -MathHelper.HALF_PI; + part.pivotY = MathHelper.sin(ageInTicks * 0.05F) - 3; + part.pivotZ = MathHelper.cos(ageInTicks * 0.045F); + + //part.yaw = (float)entity.getVelocity().getX(); + + head.pitch = headPitch * MathHelper.RADIANS_PER_DEGREE; + head.yaw = netHeadYaw * MathHelper.RADIANS_PER_DEGREE; + + lowerJaw.resetTransform(); + float jawsOpenAmount = (1 - Math.max(0, MathHelper.sin(ageInTicks * 0.1F))); + lowerJaw.pivotY -= jawsOpenAmount * 3; + lowerJaw.pivotX -= jawsOpenAmount * 3; + lowerJaw.roll += jawsOpenAmount - 0.9F; + + upperJaw.resetTransform(); + upperJaw.roll -= jawsOpenAmount * 0.2F; + + body.roll = limbSwingAmount * 0.3F; + } + + @Override + public void render(MatrixStack matrices, VertexConsumer vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha) { + part.render(matrices, vertexConsumer, light, overlay, red, green, blue, alpha); + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/entity/SombraEntityRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SombraEntityRenderer.java new file mode 100644 index 00000000..f65f92e6 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/entity/SombraEntityRenderer.java @@ -0,0 +1,25 @@ +package com.minelittlepony.unicopia.client.render.entity; + +import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.entity.SombraEntity; +import net.minecraft.client.render.entity.EntityRendererFactory; +import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.util.Identifier; + +public class SombraEntityRenderer extends LivingEntityRenderer { + private static final Identifier TEXTURE = Unicopia.id("textures/entity/sombra/head.png"); + + public SombraEntityRenderer(EntityRendererFactory.Context context) { + super(context, new SombraEntityModel(SombraEntityModel.getTexturedModelData().createModel()), 0); + } + + @Override + public Identifier getTexture(SombraEntity entity) { + return TEXTURE; + } + + @Override + protected boolean hasLabel(SombraEntity targetEntity) { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/com/minelittlepony/unicopia/entity/SombraEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/SombraEntity.java new file mode 100644 index 00000000..dea032fc --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/SombraEntity.java @@ -0,0 +1,324 @@ +package com.minelittlepony.unicopia.entity; + +import java.util.Optional; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.item.AmuletItem; +import com.minelittlepony.unicopia.item.UItems; +import com.minelittlepony.unicopia.particle.SphereParticleEffect; +import com.minelittlepony.unicopia.particle.UParticles; +import com.minelittlepony.unicopia.util.VecHelper; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.goal.ActiveTargetGoal; +import net.minecraft.entity.ai.goal.AttackGoal; +import net.minecraft.entity.ai.goal.LookAroundGoal; +import net.minecraft.entity.ai.goal.LookAtEntityGoal; +import net.minecraft.entity.ai.goal.PounceAtTargetGoal; +import net.minecraft.entity.ai.goal.RevengeGoal; +import net.minecraft.entity.ai.goal.WanderAroundGoal; +import net.minecraft.entity.ai.pathing.EntityNavigation; +import net.minecraft.entity.ai.pathing.MobNavigation; +import net.minecraft.entity.attribute.DefaultAttributeContainer; +import net.minecraft.entity.attribute.EntityAttributes; +import net.minecraft.entity.boss.BossBar; +import net.minecraft.entity.boss.ServerBossBar; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.data.DataTracker; +import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandlerRegistry; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.passive.IronGolemEntity; +import net.minecraft.entity.passive.MerchantEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtHelper; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.registry.tag.*; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.event.GameEvent; + +public class SombraEntity extends HostileEntity { + + private static final TrackedData> HOME_POS = DataTracker.registerData(SombraEntity.class, TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS); + + private final ServerBossBar bossBar = (ServerBossBar)new ServerBossBar(getDisplayName(), BossBar.Color.PURPLE, BossBar.Style.PROGRESS) + .setDarkenSky(true) + .setThickenFog(true); + + public SombraEntity(EntityType type, World world) { + super(type, world); + bossBar.setStyle(BossBar.Style.NOTCHED_10); + } + + public static DefaultAttributeContainer.Builder createMobAttributes() { + return HostileEntity.createMobAttributes() + .add(EntityAttributes.GENERIC_MAX_HEALTH, 2000) + .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 102); + } + + @Override + protected Entity.MoveEffect getMoveEffect() { + return Entity.MoveEffect.NONE; + } + + @Override + public boolean canAvoidTraps() { + return true; + } + + @Override + protected SoundEvent getHurtSound(DamageSource source) { + return SoundEvents.ENTITY_WARDEN_HURT; + } + + @Override + protected SoundEvent getDeathSound() { + return SoundEvents.ENTITY_WARDEN_DEATH; + } + + @Override + protected void initDataTracker() { + super.initDataTracker(); + dataTracker.startTracking(HOME_POS, Optional.empty()); + } + + @Override + protected void initGoals() { + goalSelector.add(5, new WanderAroundGoal(this, 1)); + goalSelector.add(6, new LookAtEntityGoal(this, PlayerEntity.class, 8F)); + goalSelector.add(7, new LookAroundGoal(this)); + goalSelector.add(8, new PounceAtTargetGoal(this, 0.3f)); + goalSelector.add(8, new AttackGoal(this)); + targetSelector.add(1, new RevengeGoal(this)); + targetSelector.add(2, new ActiveTargetGoal<>(this, PlayerEntity.class, false)); + targetSelector.add(3, new ActiveTargetGoal<>(this, MerchantEntity.class, false)); + targetSelector.add(3, new ActiveTargetGoal<>(this, IronGolemEntity.class, true)); + } + + + @Override + protected EntityNavigation createNavigation(World world) { + MobNavigation nav = new MobNavigation(this, world); + nav.setCanPathThroughDoors(true); + nav.setCanSwim(true); + nav.setCanEnterOpenDoors(true); + return nav; + } + + public Optional getHomePos() { + return dataTracker.get(HOME_POS); + } + + public void setHomePos(BlockPos pos) { + dataTracker.set(HOME_POS, Optional.of(pos)); + } + + @Override + public void tick() { + + Optional homePos = getHomePos(); + + if (homePos.isEmpty() && !isRemoved()) { + remove(RemovalReason.DISCARDED); + return; + } + + if (this.getBlockPos().getSquaredDistance(homePos.get()) > 16) { + teleportTo(Vec3d.ofCenter(homePos.get())); + setTarget(null); + } + + super.tick(); + + addVelocity(0, 0.002F, 0); + if (isSubmergedInWater()) { + jump(); + } + + if (age % 50 == 0) { + playSound(SoundEvents.ENTITY_POLAR_BEAR_AMBIENT, 3, 0.3F); + } + + if (age % 125 == 0) { + playSound(SoundEvents.AMBIENT_CAVE.value(), 1, 0.3F); + } + + if (getWorld().isClient) { + float range = 9; + for (int i = 0; i < 3; i++) { + var particle = new SphereParticleEffect(UParticles.SPHERE, + 0x222222, + 0.7F, + (float)getWorld().getRandom().nextTriangular(2.5F, 0.7F) + ); + getWorld().addParticle(particle, + getWorld().getRandom().nextTriangular(getX(), range), + getWorld().getRandom().nextTriangular(getY(), range), + getWorld().getRandom().nextTriangular(getZ(), range), + getWorld().getRandom().nextGaussian() / 6F, + getWorld().getRandom().nextGaussian() / 6F, + getWorld().getRandom().nextGaussian() / 6F + ); + } + + for (int i = 0; i < 13; i++) { + getWorld().addParticle(ParticleTypes.LARGE_SMOKE, + getWorld().getRandom().nextTriangular(getX(), 1), + getWorld().getRandom().nextTriangular(getY(), 1), + getWorld().getRandom().nextTriangular(getZ(), 1), + 0, + 0, + 0 + ); + } + } + + getWorld().getOtherEntities(this, this.getBoundingBox().expand(5), EntityPredicates.VALID_LIVING_ENTITY).forEach(target -> { + ((LivingEntity)target).addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, 100, 1)); + }); + } + + @Override + protected void mobTick() { + super.mobTick(); + bossBar.setPercent(getHealth() / getMaxHealth()); + } + + @Override + public boolean shouldRender(double distance) { + double d = 64 * getRenderDistanceMultiplier(); + return distance < d * d; + } + + @Override + public boolean isPushable() { + return false; + } + + @Override + protected void pushAway(Entity entity) { + + } + + @Override + protected void tickCramming() { + + } + + @Override + public boolean handleFallDamage(float distance, float damageMultiplier, DamageSource cause) { + return false; + } + + @Override + public boolean damage(DamageSource source, float amount) { + if (source.getAttacker() instanceof PlayerEntity player) { + if (AmuletSelectors.ALICORN_AMULET.test(player)) { + if (!getWorld().isClient) { + player.sendMessage(Text.translatable("entity.unicopia.sombra.taunt")); + } + } + ItemStack amulet = AmuletItem.getForEntity(player); + if (amulet.isOf(UItems.ALICORN_AMULET)) { + amulet.decrement(1); + } + } + boolean damaged = super.damage(source, amount); + + if (source.getAttacker() instanceof PlayerEntity player) { + teleportRandomly(16); + } + + return damaged; + } + + @Override + protected void fall(double y, boolean onGroundIn, BlockState state, BlockPos pos) { + } + + protected boolean teleportRandomly(int maxDistance) { + if (getWorld().isClient() || !isAlive()) { + return false; + } + return teleportTo(getPos().add(VecHelper.supply(() -> random.nextTriangular(0, maxDistance)))); + } + + private boolean teleportTo(Vec3d destination) { + Vec3d oldPos = getPos(); + if (canTeleportTo(destination) && teleport(destination.x, destination.y, destination.z, true)) { + getWorld().emitGameEvent(GameEvent.TELEPORT, oldPos, GameEvent.Emitter.of(this)); + return true; + } + return false; + } + + @SuppressWarnings("deprecation") + private boolean canTeleportTo(Vec3d destination) { + BlockPos.Mutable mutable = new BlockPos.Mutable(destination.x, destination.y, destination.z); + while (mutable.getY() > getWorld().getBottomY() && !getWorld().getBlockState(mutable).blocksMovement()) { + mutable.move(Direction.DOWN); + } + BlockState destinationState = getWorld().getBlockState(mutable); + return destinationState.blocksMovement() && !destinationState.getFluidState().isIn(FluidTags.WATER); + } + + @Override + @Deprecated + public float getBrightnessAtEyes() { + return super.getBrightnessAtEyes() * 0.2F; + } + + @Override + public void setCustomName(@Nullable Text name) { + super.setCustomName(name); + bossBar.setName(getDisplayName()); + } + + @Override + public void onStartedTrackingBy(ServerPlayerEntity player) { + super.onStartedTrackingBy(player); + bossBar.addPlayer(player); + } + + @Override + public void onStoppedTrackingBy(ServerPlayerEntity player) { + super.onStoppedTrackingBy(player); + bossBar.removePlayer(player); + } + + @Override + public void writeCustomDataToNbt(NbtCompound nbt) { + super.writeCustomDataToNbt(nbt); + getHomePos().map(NbtHelper::fromBlockPos).ifPresent(pos -> { + nbt.put("homePos", pos); + }); + } + + @Override + public void readCustomDataFromNbt(NbtCompound nbt) { + super.readCustomDataFromNbt(nbt); + if (nbt.contains("homePos", NbtElement.COMPOUND_TYPE)) { + setHomePos(NbtHelper.toBlockPos(nbt.getCompound("homePos"))); + } + if (hasCustomName()) { + bossBar.setName(getDisplayName()); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/UEntities.java b/src/main/java/com/minelittlepony/unicopia/entity/UEntities.java index d2d60917..b4f923a5 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/UEntities.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/UEntities.java @@ -46,6 +46,9 @@ public interface UEntities { EntityType SPELLBOOK = register("spellbook", FabricEntityTypeBuilder.create(SpawnGroup.MISC, SpellbookEntity::new) .trackRangeBlocks(200) .dimensions(EntityDimensions.fixed(0.9F, 0.5F))); + EntityType SOMBRA = register("sombra", FabricEntityTypeBuilder.create(SpawnGroup.MONSTER, SombraEntity::new) + .trackRangeBlocks(200) + .dimensions(EntityDimensions.fixed(1F, 1F))); EntityType AIR_BALLOON = register("air_balloon", FabricEntityTypeBuilder.create(SpawnGroup.MISC, AirBalloonEntity::new) .trackRangeBlocks(1000) .dimensions(EntityDimensions.changing(2.5F, 0.1F))); @@ -60,6 +63,7 @@ public interface UEntities { FabricDefaultAttributeRegistry.register(SPELLBOOK, SpellbookEntity.createMobAttributes()); FabricDefaultAttributeRegistry.register(TWITTERMITE, FairyEntity.createMobAttributes()); FabricDefaultAttributeRegistry.register(AIR_BALLOON, FlyingEntity.createMobAttributes()); + FabricDefaultAttributeRegistry.register(SOMBRA, SombraEntity.createMobAttributes()); if (!Unicopia.getConfig().disableButterflySpawning.get()) { final Predicate butterflySpawnable = BiomeSelectors.foundInOverworld() diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index 0850d8cc..76b63856 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -197,6 +197,8 @@ "entity.unicopia.cast_spell": "Cast Spell", "entity.unicopia.cast_spell.by": "a spell cast by %s", "entity.unicopia.spellbook": "Spellbook", + "entity.unicopia.sombra": "King Sombra", + "entity.unicopia.sombra.taunt": "That's not going to work on me!", "player.reachDistance": "Reach Distance", "player.miningSpeed": "Mining Speed", diff --git a/src/main/resources/assets/unicopia/textures/entity/sombra/head.png b/src/main/resources/assets/unicopia/textures/entity/sombra/head.png new file mode 100644 index 00000000..55774f8e Binary files /dev/null and b/src/main/resources/assets/unicopia/textures/entity/sombra/head.png differ