Merge branch '1.20.2' into 1.20.4

# Conflicts:
#	build.gradle
#	gradle.properties
#	src/main/java/com/minelittlepony/unicopia/advancement/CustomEventCriterion.java
#	src/main/java/com/minelittlepony/unicopia/advancement/RacePredicate.java
#	src/main/java/com/minelittlepony/unicopia/advancement/SendViaDragonBreathScrollCriterion.java
#	src/main/java/com/minelittlepony/unicopia/block/cloud/CloudPillarBlock.java
#	src/main/java/com/minelittlepony/unicopia/datagen/providers/URecipeProvider.java
#	src/main/java/com/minelittlepony/unicopia/diet/affliction/StatusEffectAffliction.java
#	src/main/java/com/minelittlepony/unicopia/item/HeavyProjectileItem.java
#	src/main/resources/data/unicopia/tags/items/food_types/forage_nauseating.json
This commit is contained in:
Sollace 2024-04-05 22:01:26 +01:00
commit 1980cf634e
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
678 changed files with 8204 additions and 11920 deletions

View file

@ -17,6 +17,10 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 17
- name: Prepare Datagen
uses: eskatos/gradle-command-action@v1
with:
arguments: rundatagen
- name: Publish Modrinth Jar
env:
MODRINTH_KEY: ${{ secrets.MODRINTH_KEY }}

BIN
assets/models/body.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

BIN
assets/models/cork.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

File diff suppressed because one or more lines are too long

View 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);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -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"}
}
}
]
}

View file

@ -0,0 +1 @@
{"meta":{"format_version":"4.9","model_format":"java_block","box_uv":false},"name":"jar","parent":"","ambientocclusion":true,"front_gui_light":false,"visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"unhandled_root_fields":{},"resolution":{"width":16,"height":16},"elements":[{"name":"cube","box_uv":false,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[4,0,4],"to":[12,12,12],"autouv":0,"color":3,"origin":[0,0,0],"faces":{"north":{"uv":[0,0,8,12],"texture":0},"east":{"uv":[0,0,8,12],"texture":0},"south":{"uv":[0,0,8,12],"texture":0},"west":{"uv":[0,0,8,12],"texture":0},"up":{"uv":[8,0,16,8],"texture":0},"down":{"uv":[8,0,16,8],"texture":0}},"type":"cube","uuid":"c02d32c0-74ac-27ba-627e-83de2a9500f7"},{"name":"cube","box_uv":false,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[6,13,6],"to":[10,16,10],"autouv":0,"color":3,"origin":[0,0,0],"faces":{"north":{"uv":[0,4,4,7],"texture":1},"east":{"uv":[0,4,4,7],"texture":1},"south":{"uv":[0,4,4,7],"texture":1},"west":{"uv":[0,4,4,7],"texture":1},"up":{"uv":[0,0,4,4],"texture":1},"down":{"uv":[4,0,8,4],"texture":1}},"type":"cube","uuid":"147c96d5-ae15-7e40-dcb7-c635e6e80eed"},{"name":"cube","box_uv":false,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[5,13,5],"to":[11,14,11],"autouv":0,"color":3,"origin":[0,0,0],"faces":{"north":{"uv":[0,0,8,1],"texture":0},"east":{"uv":[0,0,8,1],"texture":0},"south":{"uv":[0,0,8,1],"texture":0},"west":{"uv":[0,0,8,1],"texture":0},"up":{"uv":[8,0,16,8],"texture":0},"down":{"uv":[8,0,16,8],"texture":0}},"type":"cube","uuid":"7642fef8-ce7e-d79f-f450-01de2526fca5"},{"name":"cube","box_uv":false,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[6,12,6],"to":[10,13,10],"autouv":0,"color":3,"origin":[0,0,0],"faces":{"north":{"uv":[0,0,8,1],"texture":0},"east":{"uv":[0,0,8,1],"texture":0},"south":{"uv":[0,0,8,1],"texture":0},"west":{"uv":[0,0,8,1],"texture":0},"up":{"uv":[8,0,16,8],"texture":0},"down":{"uv":[8,0,16,8],"texture":0}},"type":"cube","uuid":"e1e878a3-7fdb-79f6-e2c8-b591a94cec41"}],"outliner":["c02d32c0-74ac-27ba-627e-83de2a9500f7","7642fef8-ce7e-d79f-f450-01de2526fca5","e1e878a3-7fdb-79f6-e2c8-b591a94cec41","147c96d5-ae15-7e40-dcb7-c635e6e80eed"],"textures":[{"path":"","name":"body","folder":"block","namespace":"","id":"0","width":16,"height":16,"uv_width":16,"uv_height":16,"particle":true,"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":false,"uuid":"c3fc3ff5-2bb6-a5d1-88ff-7d0d48a4200c","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAKxJREFUOE/Nk70NxCAMhe0qiCKCCRiA/UdhAFgARIGg8sknJbpI/CS6K47Sz/54fggkIoLJCSHAvu+glLp0pZQg5wwYYyStNfYYrHGdhxHx0sMXM+QEHIVPGAN6w8dlPHMCek4eAUYrLB1478kYM8zga8AyxJkD1hgwfcYVYLTekRk658ha281gpv0WUEqBWiu01t7gbdtACAFSShi5Ox3M/sEdrbv7ncH/cfACoGWX3cV5e7AAAAAASUVORK5CYII="},{"path":"","name":"cork","folder":"block","namespace":"","id":"1","width":16,"height":16,"uv_width":16,"uv_height":16,"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":false,"uuid":"1faf1369-230e-ed4a-f210-037c1820f194","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAFJJREFUOE9jXDwj8z8DHhCbMZ0RnzwjyABRYW6wmtdvv4JpZD59DKDICztWl6CEgUdoD14/o1sGDgNkQUJ+pr4B+PxPjBxJ/sVm4KgBDAzDIAwAlBIoEQohE0IAAAAASUVORK5CYII="}]}

BIN
assets/models/jar_body.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

File diff suppressed because one or more lines are too long

BIN
assets/models/jar_cork.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

View file

@ -0,0 +1 @@
{"meta":{"format_version":"4.9","model_format":"java_block","box_uv":false},"name":"jar","parent":"","ambientocclusion":true,"front_gui_light":false,"visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"unhandled_root_fields":{},"resolution":{"width":16,"height":16},"elements":[{"name":"cube","box_uv":false,"rescale":true,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[6,1,7.5],"to":[11,11,7.5],"autouv":0,"color":5,"rotation":[0,-45,0],"origin":[8,5,7],"faces":{"north":{"uv":[3,0,13,16],"texture":0},"east":{"uv":[0,0,0,8],"texture":0},"south":{"uv":[3,0,13,16],"texture":0},"west":{"uv":[0,0,0,8],"texture":0},"up":{"uv":[0,0,6,0],"texture":0},"down":{"uv":[0,0,6,0],"texture":0}},"type":"cube","uuid":"52fdb109-7055-1f3c-d1a1-788daf976643"},{"name":"cube","box_uv":false,"rescale":true,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[5,1,7.5],"to":[10,11,7.5],"autouv":0,"color":5,"rotation":[0,45,0],"origin":[8,5,7],"faces":{"north":{"uv":[3,0,13,16],"texture":0},"east":{"uv":[0,0,0,8],"texture":0},"south":{"uv":[3,0,13,16],"texture":0},"west":{"uv":[0,0,0,8],"texture":0},"up":{"uv":[0,0,6,0],"rotation":180,"texture":0},"down":{"uv":[0,0,6,0],"rotation":180,"texture":0}},"type":"cube","uuid":"67ba2407-52e4-4b13-579c-0e7675265bb9"}],"outliner":["52fdb109-7055-1f3c-d1a1-788daf976643","67ba2407-52e4-4b13-579c-0e7675265bb9"],"textures":[{"path":"/home/sollace/Documents/GitRepos/minecraft_mods/Unicopia/src/main/resources/assets/unicopia/textures/block/lightning_jar_filling.png","name":"lightning_jar_filling.png","folder":"block","namespace":"unicopia","id":"2","width":16,"height":16,"uv_width":16,"uv_height":16,"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":"2c8fdd18-9bd4-2276-cdc1-d86d0605d22d","relative_path":"../../../src/main/resources/assets/unicopia/textures/block/lightning_jar_filling.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAN9JREFUOE9jZCASOH7T/L+f6zojunIMAWzmObxR/c/IxcJAlgE+3/X+f/j7l4GV6R/pBnh/0vv/59d/hl9cf7BqBrkWrxdABnxj+Y1TM14DQJq//vrOwMfLz7CJ/QxOi7BKgEKc5wcLw3u2fwxHeK6C1YDEuP6wMqC7CKcB2GIDZMBWvksoejAMANmErBnkEhD4zP6bgZGRESM88BoA1/zvBzi8D4jcwp+QkG0HJRrfd7pg14DCgqh0ADMApBnEZvsGcT5Z6QBXqBOVF9C9gi+/4Y1GbJmHoAuQw4GYnA4AMBBxEZobGUEAAAAASUVORK5CYII="}]}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"meta":{"format_version":"4.9","model_format":"java_block","box_uv":false},"name":"jar","parent":"","ambientocclusion":true,"front_gui_light":false,"visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"unhandled_root_fields":{},"resolution":{"width":16,"height":16},"elements":[{"name":"cube","box_uv":false,"rescale":false,"locked":false,"render_order":"default","allow_mirror_modeling":true,"from":[4,0,4],"to":[12,10,12],"autouv":0,"color":4,"inflate":-0.09999999999999964,"origin":[0,0,0],"faces":{"north":{"uv":[0,2,8,12],"texture":2},"east":{"uv":[0,6,8,16],"texture":2},"south":{"uv":[8,6,16,16],"texture":2},"west":{"uv":[8,0,16,10],"texture":2},"up":{"uv":[4,3,12,11],"texture":2},"down":{"uv":[8,4,16,12],"texture":2}},"type":"cube","uuid":"e15b3907-6195-1f3b-0c48-23c6b4642fc6"}],"outliner":["e15b3907-6195-1f3b-0c48-23c6b4642fc6"],"textures":[{"path":"/home/sollace/Documents/GitRepos/minecraft_mods/Unicopia/assets/models/body.png","name":"body.png","folder":"","namespace":"","id":"0","width":16,"height":16,"uv_width":16,"uv_height":16,"particle":true,"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":"c3fc3ff5-2bb6-a5d1-88ff-7d0d48a4200c","relative_path":"../body.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAKxJREFUOE/Nk70NxCAMhe0qiCKCCRiA/UdhAFgARIGg8sknJbpI/CS6K47Sz/54fggkIoLJCSHAvu+glLp0pZQg5wwYYyStNfYYrHGdhxHx0sMXM+QEHIVPGAN6w8dlPHMCek4eAUYrLB1478kYM8zga8AyxJkD1hgwfcYVYLTekRk658ha281gpv0WUEqBWiu01t7gbdtACAFSShi5Ox3M/sEdrbv7ncH/cfACoGWX3cV5e7AAAAAASUVORK5CYII="},{"path":"/home/sollace/Documents/GitRepos/minecraft_mods/Unicopia/assets/models/cork.png","name":"cork.png","folder":"","namespace":"","id":"1","width":16,"height":16,"uv_width":16,"uv_height":16,"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":"1faf1369-230e-ed4a-f210-037c1820f194","relative_path":"../cork.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAFJJREFUOE9jXDwj8z8DHhCbMZ0RnzwjyABRYW6wmtdvv4JpZD59DKDICztWl6CEgUdoD14/o1sGDgNkQUJ+pr4B+PxPjBxJ/sVm4KgBDAzDIAwAlBIoEQohE0IAAAAASUVORK5CYII="},{"path":"/home/sollace/Documents/GitRepos/minecraft_mods/Unicopia/src/main/resources/assets/unicopia/textures/item/jar_filling_zap.png","name":"jar_filling_zap.png","folder":"item","namespace":"unicopia","id":"2","width":16,"height":16,"uv_width":16,"uv_height":16,"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":false,"uuid":"62c06d20-77c5-befb-bb95-8e5da5394d9c","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAudJREFUOE8dkUlrXWUYgJ/3G849J7dJSxZuG2s6aMDaUsWWNjVpBS2luHDtyp1UcOhfEKTZ1LYIURQXjQYkEkwduhVd6S8oxUXAJpCBeO/NGb7hlfgPnkHOmvfUiMepBwJ3ph0ej3YRPew5+9UnSN9CY4gnL0FpcBo5vzjCeEHOmA9UJaBJuTftKHAUGeoqc/7BPTgUyPsgJ+boTEEkU6rj3OJTysIiZ/37moPly5mSnjEgBYN2n5d/+RSXgAQ5QDw5R2GFQWOZ/WIL6Ql2lJFz9iNdfM4zsg3jFAy6louP7kMRyZ2AgfqZWXAlRlsuLw7wpdDEQH10Ffnj+C31PY+2LT4Lp79fgBIkQZICfeEyQSsYNlxZ3mX4b83EkYqm6Rge/wn569SHqjZRq+fC6gK66Vgff5ep9A3MzLLTBY5UgVcXa1KKRBImQH5xDVGH/Pn8LTUkXvr5M1I0uKbj73yTZ48/IfmEsZFXvt6jGAniDYOwTz72A9rvQzbI76c+1gs/3icMa/wERAE3dYOailwPmFvbxu5kJBz0F0ZnVkl1S9Xr0wWD6GOUCCogCvnYWxjfgkZeX27Y3tzDO0cMGTPzkNh3tHVNUULvtbtIfoKKeNLUVYwYJEW6kePGbyM2Hm9RVI5oDGlqhewMgsWKoXd1gUiH1GFeSyvQjJGrhjeWO/55uoVTh+9bjGTs9K80YmhDTRk69PodnPW0MSIarimu4NrKiO31baJP9IqCHJV4Yol8gC8lsR5Qjo1Tzt2mIRNjwHhF3vzuinaaECvs7uxgjaE6+pCNPGRsYpxcJ9QbNAYmr37Org7pmTFaavyB8vzSrDpbsbe5RVNF3NEVovXQtPjeIVpa3t7cYO2dbzHqyKYhqSekfUpXIReXLqlJke3JB7geqHdIryDWSmkjxlYcnr/NXmhIVrCq/H/NZBwVcvrRunYSKLGkImOi4LynDcrk9bsMm33koIFrKUIP1Y7sWqz0ydLyH7DGczPZHbGfAAAAAElFTkSuQmCC","relative_path":"../../../src/main/resources/assets/unicopia/textures/item/jar_filling_zap.png"}]}

View file

@ -27,18 +27,13 @@ archivesBaseName = project.name
loom {
mixin.defaultRefmapName = 'unicopia.mixin.refmap.json'
accessWidenerPath = file('src/main/resources/unicopia.aw')
runs {
datagen {
server()
name "Data Generation"
vmArg "-Dfabric-api.datagen"
vmArg "-Dfabric-api.datagen.modid=unicopia"
vmArg "-Dfabric-api.datagen.output-dir=${file("src/main/generated")}"
runDir "build/datagen"
}
}
fabricApi {
configureDataGeneration {
modId = 'unicopia'
}
}
//assemble.dependsOn(runDatagen)
reckon {
scopeFromProp()
@ -48,13 +43,15 @@ reckon {
repositories {
mavenLocal()
flatDir { dirs 'lib' }
maven { name 'entity-reach-attributes'; url 'https://maven.jamieswhiteshirt.com/libs-release' }
maven { name 'entity-reach-attributes'; url 'https://maven.jamieswhiteshirt.com/libs-release'; content { includeGroup "com.jamieswhiteshirt" } }
maven { name 'trinkets'; url 'https://maven.ladysnake.org/releases' }
maven { name 'mod-menu'; url 'https://maven.terraformersmc.com/' }
maven { name 'minelp-snapshot'; url 'https://repo.minelittlepony-mod.com/maven/snapshot' }
maven { name 'minelp-releases'; url 'https://repo.minelittlepony-mod.com/maven/release' }
maven { name 'TerraformersMC'; url 'https://maven.terraformersmc.com/' }
maven { name 'Nodium'; url 'https://maven.cafeteria.dev/releases/' }
maven { name 'Greenhouse Maven For Farmers delight'; url 'https://maven.greenhouseteam.dev/releases/' }
maven { name 'Porting Lib For Farmers delight'; url = 'https://mvn.devos.one/releases/' }
maven { name 'Modrinth'; url 'https://api.modrinth.com/maven' }
maven { name 'JitPack'; url 'https://jitpack.io'; content { includeGroup "com.github.Virtuoel" } }
}
@ -90,7 +87,9 @@ dependencies {
modImplementation "me.luligabi:NoIndium:${project.nodium_version}"
include "me.luligabi:NoIndium:${project.nodium_version}"
//modCompileOnly "maven.modrinth:farmers-delight-fabric:${project.farmers_delight_version}", { exclude group: "net.fabricmc.fabric-api" }
//modImplementation "vectorwing:FarmersDelight-Refabricated:${project.farmers_delight_version}", {
// exclude group: "net.fabricmc"
//}
if (project.use_pehkui == '1') {
modCompileOnly "maven.modrinth:pehkui:${project.pehkui_version}", { exclude group: "net.fabricmc.fabric-api" }
modCompileOnly "com.github.Virtuoel:KanosConfig:0.4.1", { exclude group: "net.fabricmc.fabric-api" }
@ -109,12 +108,8 @@ dependencies {
}
}
sourceSets {
main {
resources {
srcDirs += [ "src/main/generated" ]
}
}
remapJar {
addNestedDependencies = true
}
processResources {

View file

@ -33,7 +33,7 @@ org.gradle.daemon=false
use_pehkui=0
use_sodium=1
farmers_delight_version=1.4.3
farmers_delight_version=1.20.1-2.0.9
pehkui_version=3.7.8+1.14.4-1.20.4
iris_version=1.6.17+1.20.4
sodium_version=mc1.20.4-0.5.8

View file

@ -51,7 +51,7 @@ public interface Debug {
)).forEach((namespace, entries) -> {
@SuppressWarnings("deprecation")
var unregistered = entries.stream()
.filter(entry -> !entry.getValue().getRegistryEntry().isIn(UTags.HAS_NO_TRAITS) && SpellTraits.of(entry.getValue()).isEmpty())
.filter(entry -> !entry.getValue().getRegistryEntry().isIn(UTags.Items.HAS_NO_TRAITS) && SpellTraits.of(entry.getValue()).isEmpty())
.map(entry -> {
String id = entry.getKey().getValue().toString();

View file

@ -22,14 +22,19 @@ public interface EquineContext {
}
default boolean collidesWithClouds() {
return getCompositeRace().any(Race::canInteractWithClouds);
return getCompositeRace().canInteractWithClouds();
}
default boolean hasFeatherTouch() {
return false;
}
static EquineContext of(ShapeContext context) {
if (context == ShapeContext.absent()) {
return Unicopia.SIDE.getPony().map(EquineContext.class::cast).orElse(ABSENT);
}
return context instanceof EquineContext c ? c : ABSENT;
EquineContext result = context instanceof Container c ? c.get() : ABSENT;
return result == null ? ABSENT : result;
}
static EquineContext of(ItemUsageContext context) {
@ -42,4 +47,8 @@ public interface EquineContext {
}
return MoreObjects.firstNonNull(Equine.of(entity).orElse(null), ABSENT);
}
interface Container {
EquineContext get();
}
}

View file

@ -20,7 +20,7 @@ public interface EquinePredicates {
Predicate<Entity> BAT = physicalRaceMatches(Race.BAT::equals);
Predicate<Entity> CHANGELING = physicalRaceMatches(Race.CHANGELING::equals);
Predicate<Entity> RACE_INTERACT_WITH_CLOUDS = raceMatches(Race::canInteractWithClouds);
Predicate<Entity> RACE_CAN_INFLUENCE_WEATHER = raceMatches(Race::canInfluenceWeather);
Predicate<Entity> RAGING = IS_PLAYER.and(SpellType.RAGE::isOn);
Predicate<Entity> PLAYER_EARTH = IS_PLAYER.and(ofRace(Race.EARTH));
@ -28,7 +28,6 @@ public interface EquinePredicates {
Predicate<Entity> PLAYER_UNICORN = IS_PLAYER.and(raceMatches(Race::canCast));
Predicate<Entity> PLAYER_CHANGELING = IS_PLAYER.and(ofRace(Race.CHANGELING));
Predicate<Entity> PLAYER_KIRIN = IS_PLAYER.and(ofRace(Race.KIRIN));
Predicate<Entity> PLAYER_PEGASUS = IS_PLAYER.and(e -> ((PlayerEntity)e).getAbilities().creativeMode || RACE_INTERACT_WITH_CLOUDS.test(e));
Predicate<Entity> PLAYER_SEAPONY = IS_PLAYER.and(raceMatches(Race::isFish));
Predicate<Entity> PLAYER_CAN_USE_EARTH = IS_PLAYER.and(raceMatches(Race::canUseEarth));

View file

@ -14,6 +14,8 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
public class InteractionManager {
@ -90,4 +92,8 @@ public class InteractionManager {
public void sendPlayerLookAngles(PlayerEntity player) {
}
public void addBlockBreakingParticles(BlockPos pos, Direction direction) {
}
}

View file

@ -80,7 +80,7 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
}
public boolean hasIronGut() {
return !isHuman() && this != CHANGELING;
return !isHuman();
}
public boolean isUnset() {
@ -108,9 +108,17 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
}
public boolean canInteractWithClouds() {
return canFly() && this != CHANGELING;
}
public boolean canInfluenceWeather() {
return canFly() && this != CHANGELING && this != BAT && this != HIPPOGRIFF;
}
public boolean hasPersistentWeatherMagic() {
return canInfluenceWeather();
}
public Identifier getId() {
return REGISTRY.getId(this);
}
@ -225,6 +233,18 @@ public record Race (Supplier<Composite> compositeSupplier, Availability availabi
return any(Race::canCast);
}
public boolean canInteractWithClouds() {
return any(Race::canInteractWithClouds);
}
public boolean canInfluenceWeather() {
return any(Race::canInfluenceWeather);
}
public boolean hasPersistentWeatherMagic() {
return any(Race::hasPersistentWeatherMagic);
}
public FlightType flightType() {
if (pseudo() == null) {
return physical().flightType();

View file

@ -7,6 +7,27 @@ import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public interface UConventionalTags {
interface Blocks {
TagKey<Block> CONCRETE_POWDERS = block("concrete_powders");
TagKey<Block> CONCRETES = block("concretes");
TagKey<Block> GLAZED_TERRACOTTAS = block("glazed_terracottas");
TagKey<Block> CORAL_BLOCKS = block("coral_blocks");
TagKey<Block> CORAL_FANS = block("coral_fans");
TagKey<Block> CORALS = block("corals");
private static TagKey<Block> block(String name) {
return TagKey.of(RegistryKeys.BLOCK, new Identifier("c", name));
}
}
interface Items {
TagKey<Item> CONCRETE_POWDERS = item("concrete_powders");
TagKey<Item> CONCRETES = item("concretes");
TagKey<Item> GLAZED_TERRACOTTAS = item("glazed_terracottas");
TagKey<Item> CORAL_BLOCKS = item("coral_blocks");
TagKey<Item> CORAL_FANS = item("coral_fans");
TagKey<Item> CORALS = item("corals");
TagKey<Item> APPLES = item("apples");
TagKey<Item> ACORNS = item("acorns");
TagKey<Item> PINECONES = item("pinecones");
@ -19,20 +40,31 @@ public interface UConventionalTags {
TagKey<Item> MUSHROOMS = item("mushrooms");
TagKey<Item> MUFFINS = item("muffins");
TagKey<Item> MANGOES = item("mangoes");
TagKey<Item> OEATMEALS = item("oatmeals");
TagKey<Item> OATMEALS = item("oatmeals");
TagKey<Item> COOKIES = item("cookies");
TagKey<Item> FRUITS = item("fruits");
TagKey<Item> WORMS = item("worms");
TagKey<Item> ROCKS = item("rocks");
TagKey<Item> RAW_INSECT = item("raw_insect");
TagKey<Item> COOKED_INSECT = item("cooked_insect");
TagKey<Item> ROTTEN_INSECT = item("rotten_insect");
TagKey<Item> RAW_FISH = item("raw_fish");
TagKey<Item> COOKED_FISH = item("cooked_fish");
TagKey<Item> ROTTEN_FISH = item("rotten_fish");
TagKey<Item> RAW_MEAT = item("raw_meat");
TagKey<Item> COOKED_MEAT = item("cooked_meat");
TagKey<Item> ROTTEN_MEAT = item("rotten_meat");
TagKey<Item> DESSERTS = item("desserts");
TagKey<Item> CANDY = item("candy");
TagKey<Item> CROPS_PEANUTS = item("crops/peanuts");
TagKey<Item> TOOL_KNIVES = item("tools/knives");
static TagKey<Item> item(String name) {
private static TagKey<Item> item(String name) {
return TagKey.of(RegistryKeys.ITEM, new Identifier("c", name));
}
static TagKey<Block> block(String name) {
return TagKey.of(RegistryKeys.BLOCK, new Identifier("c", name));
}
}

View file

@ -11,54 +11,6 @@ import net.minecraft.util.Identifier;
import net.minecraft.world.dimension.DimensionType;
public interface UTags {
TagKey<Item> FRESH_APPLES = item("fresh_apples");
TagKey<Item> FALLS_SLOWLY = item("falls_slowly");
TagKey<Item> PIES = item("pies");
TagKey<Item> CAN_CUT_PIE = item("can_cut_pie");
TagKey<Item> MAGIC_FEATHERS = item("magic_feathers");
TagKey<Item> SHADES = item("shades");
TagKey<Item> CHANGELING_EDIBLE = item("food_types/changeling_edible");
TagKey<Item> SPOOKED_MOB_DROPS = item("spooked_mob_drops");
TagKey<Item> HAS_NO_TRAITS = item("has_no_traits");
TagKey<Item> IS_DELIVERED_AGGRESSIVELY = item("is_delivered_aggressively");
TagKey<Item> FLOATS_ON_CLOUDS = item("floats_on_clouds");
TagKey<Item> COOLS_OFF_KIRINS = item("cools_off_kirins");
TagKey<Item> LOOT_BUG_HIGH_VALUE_DROPS = item("loot_bug_high_value_drops");
TagKey<Item> SHELLS = item("food_types/shells");
TagKey<Item> POLEARMS = item("polearms");
TagKey<Item> HORSE_SHOES = item("horse_shoes");
TagKey<Item> APPLE_SEEDS = item("apple_seeds");
TagKey<Item> BASKETS = item("baskets");
TagKey<Item> BADGES = item("badges");
TagKey<Item> BED_SHEETS = item("bed_sheets");
TagKey<Item> CLOUD_JARS = item("cloud_jars");
TagKey<Block> FRAGILE = block("fragile");
TagKey<Block> INTERESTING = block("interesting");
TagKey<Block> CATAPULT_IMMUNE = block("catapult_immune");
TagKey<Block> CRYSTAL_HEART_BASE = block("crystal_heart_base");
TagKey<Block> CRYSTAL_HEART_ORNAMENT = block("crystal_heart_ornament");
TagKey<Block> UNAFFECTED_BY_GROW_ABILITY = block("unaffected_by_grow_ability");
TagKey<Block> KICKS_UP_DUST = block("kicks_up_dust");
TagKey<Block> POLEARM_MINEABLE = block("mineable/polearm");
TagKey<EntityType<?>> TRANSFORMABLE_ENTITIES = entity("transformable");
TagKey<StatusEffect> PINEAPPLE_EFFECTS = effect("pineapple_effects");
TagKey<DamageType> BREAKS_SUNGLASSES = damage("breaks_sunglasses");
TagKey<DamageType> SPELLBOOK_IMMUNE_TO = damage("spellbook_immune_to");
TagKey<DimensionType> HAS_NO_ATMOSPHERE = dimension("has_no_atmosphere");
interface Items {
TagKey<Item> ZAP_LOGS = item("zap_logs");
TagKey<Item> WAXED_ZAP_LOGS = item("waxed_zap_logs");
@ -68,6 +20,67 @@ public interface UTags {
TagKey<Item> CLOUD_STAIRS = item("cloud_stairs");
TagKey<Item> CLOUD_BLOCKS = item("cloud_blocks");
TagKey<Item> CHITIN_BLOCKS = item("chitin_blocks");
TagKey<Item> FRESH_APPLES = item("fresh_apples");
TagKey<Item> FALLS_SLOWLY = item("falls_slowly");
TagKey<Item> PIES = item("pies");
TagKey<Item> CAN_CUT_PIE = item("can_cut_pie");
TagKey<Item> MAGIC_FEATHERS = item("magic_feathers");
TagKey<Item> SHADES = item("shades");
TagKey<Item> SPOOKED_MOB_DROPS = item("spooked_mob_drops");
TagKey<Item> HAS_NO_TRAITS = item("has_no_traits");
TagKey<Item> IS_DELIVERED_AGGRESSIVELY = item("is_delivered_aggressively");
TagKey<Item> CONTAINER_WITH_LOVE = item("container_with_love");
TagKey<Item> FLOATS_ON_CLOUDS = item("floats_on_clouds");
TagKey<Item> COOLS_OFF_KIRINS = item("cools_off_kirins");
TagKey<Item> LOOT_BUG_COMMON_DROPS = item("loot_bug_common_drops");
TagKey<Item> LOOT_BUG_RARE_DROPS = item("loot_bug_rare_drops");
TagKey<Item> LOOT_BUG_EPIC_DROPS = item("loot_bug_epic_drops");
TagKey<Item> SHELLS = item("shells");
TagKey<Item> SPECIAL_SHELLS = item("special_shells");
TagKey<Item> ROCK_STEWS = item("rock_stews");
TagKey<Item> BAKED_GOODS = item("baked_goods");
TagKey<Item> HIGH_QUALITY_SEA_VEGETABLES = item("food_types/high_quality_sea_vegetables");
TagKey<Item> LOW_QUALITY_SEA_VEGETABLES = item("food_types/low_quality_sea_vegetables");
TagKey<Item> POLEARMS = item("polearms");
TagKey<Item> HORSE_SHOES = item("horse_shoes");
TagKey<Item> APPLE_SEEDS = item("apple_seeds");
TagKey<Item> BASKETS = item("baskets");
TagKey<Item> BADGES = item("badges");
TagKey<Item> WOOL_BED_SHEETS = item("wool_bed_sheets");
TagKey<Item> BED_SHEETS = item("bed_sheets");
TagKey<Item> CLOUD_JARS = item("cloud_jars");
TagKey<Item> GROUP_FORAGING = item("groups/foraging");
TagKey<Item> GROUP_EARTH_PONY = item("groups/earth_pony");
TagKey<Item> GROUP_UNICORN = item("groups/unicorn");
TagKey<Item> GROUP_PEGASUS = item("groups/pegasus");
TagKey<Item> GROUP_BAT_PONY = item("groups/bat_pony");
TagKey<Item> GROUP_SEA_PONY = item("groups/sea_pony");
TagKey<Item> GROUP_CHANGELING = item("groups/changeling");
TagKey<Item> FORAGE_BLINDING = item("forage/blinding");
TagKey<Item> FORAGE_DANGEROUS = item("forage/dangerous");
TagKey<Item> FORAGE_FILLING = item("forage/filling");
TagKey<Item> FORAGE_SAFE = item("forage/safe");
TagKey<Item> FORAGE_NAUSEATING = item("forage/nauseating");
TagKey<Item> FORAGE_PRICKLY = item("forage/prickly");
TagKey<Item> FORAGE_GLOWING = item("forage/glowing");
TagKey<Item> FORAGE_RISKY = item("forage/risky");
TagKey<Item> FORAGE_STRENGHENING = item("forage/strenghtening");
TagKey<Item> FORAGE_SEVERE_NAUSEATING = item("forage/severe/nauseating");
TagKey<Item> FORAGE_SEVERE_PRICKLY = item("forage/severe/prickly");
private static TagKey<Item> item(String name) {
return TagKey.of(RegistryKeys.ITEM, Unicopia.id(name));
}
}
interface Blocks {
@ -79,29 +92,58 @@ public interface UTags {
TagKey<Block> CLOUD_STAIRS = block("cloud_stairs");
TagKey<Block> CLOUD_BLOCKS = block("cloud_blocks");
TagKey<Block> CHITIN_BLOCKS = block("chitin_blocks");
}
static TagKey<Item> item(String name) {
return TagKey.of(RegistryKeys.ITEM, Unicopia.id(name));
}
TagKey<Block> FRAGILE = block("fragile");
TagKey<Block> INTERESTING = block("interesting");
TagKey<Block> CATAPULT_IMMUNE = block("catapult_immune");
TagKey<Block> JARS = block("jars");
static TagKey<Block> block(String name) {
TagKey<Block> CRYSTAL_HEART_BASE = block("crystal_heart_base");
TagKey<Block> CRYSTAL_HEART_ORNAMENT = block("crystal_heart_ornament");
TagKey<Block> UNAFFECTED_BY_GROW_ABILITY = block("unaffected_by_grow_ability");
TagKey<Block> KICKS_UP_DUST = block("kicks_up_dust");
TagKey<Block> POLEARM_MINEABLE = block("mineable/polearm");
TagKey<Block> BUTTERFLIES_SPAWNABLE_ON = block("butterflies_spawn_on");
private static TagKey<Block> block(String name) {
return TagKey.of(RegistryKeys.BLOCK, Unicopia.id(name));
}
}
static TagKey<EntityType<?>> entity(String name) {
interface Entities {
TagKey<EntityType<?>> TRANSFORMABLE = entity("transformable");
private static TagKey<EntityType<?>> entity(String name) {
return TagKey.of(RegistryKeys.ENTITY_TYPE, Unicopia.id(name));
}
static TagKey<StatusEffect> effect(String name) {
return TagKey.of(RegistryKeys.STATUS_EFFECT, Unicopia.id(name));
}
static TagKey<DamageType> damage(String name) {
interface DamageTypes {
TagKey<DamageType> BREAKS_SUNGLASSES = damage("breaks_sunglasses");
TagKey<DamageType> SPELLBOOK_IMMUNE_TO = damage("spellbook_immune_to");
TagKey<DamageType> FROM_ROCKS = damage("from_rocks");
TagKey<DamageType> FROM_HORSESHOES = damage("from_horseshoes");
private static TagKey<DamageType> damage(String name) {
return TagKey.of(RegistryKeys.DAMAGE_TYPE, Unicopia.id(name));
}
}
static TagKey<DimensionType> dimension(String name) {
interface DimensionTypes {
TagKey<DimensionType> HAS_NO_ATMOSPHERE = dimension("has_no_atmosphere");
private static TagKey<DimensionType> dimension(String name) {
return TagKey.of(RegistryKeys.DIMENSION_TYPE, new Identifier("c", name));
}
}
interface StatusEffects {
TagKey<StatusEffect> PINEAPPLE_EFFECTS = effect("pineapple_effects");
private static TagKey<StatusEffect> effect(String name) {
return TagKey.of(RegistryKeys.STATUS_EFFECT, Unicopia.id(name));
}
}
}

View file

@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
@ -79,6 +80,7 @@ public class ChangeFormAbility implements Ability<Hit> {
Race actualRace = isTransforming ? target.getSpecies() : Race.UNSET;
target.setSpecies(supressed.or(player.getCompositeRace().potential()));
target.setSuppressedRace(actualRace);
UCriteria.SEAPONY_TRANSITION.trigger(target.asEntity());
}
});

View file

@ -2,26 +2,22 @@ package com.minelittlepony.unicopia.ability;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.TraceHelper;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.passive.CowEntity;
import net.minecraft.entity.passive.MerchantEntity;
@ -34,6 +30,13 @@ import net.minecraft.particle.ParticleTypes;
* Changeling ability to restore health from mobs
*/
public class ChangelingFeedAbility implements Ability<Hit> {
private static final Predicate<Entity> TARGET_PREDICATE = e -> (e instanceof LivingEntity)
&& (e instanceof CowEntity
|| e instanceof MerchantEntity
|| e instanceof PlayerEntity
|| e instanceof SheepEntity
|| e instanceof PigEntity
|| e instanceof HostileEntity);
@Override
public int getWarmupTime(Pony player) {
@ -42,7 +45,7 @@ public class ChangelingFeedAbility implements Ability<Hit> {
@Override
public int getCooldownTime(Pony player) {
return canFeed(player) ? 15 : 80;
return !SpellType.FEED.isOn(player) && ChangelingFeedingSpell.canFeed(player) ? 15 : 80;
}
@Override
@ -53,22 +56,7 @@ public class ChangelingFeedAbility implements Ability<Hit> {
@Nullable
@Override
public Optional<Hit> prepare(Pony player) {
return Hit.of(canFeed(player) && !getTargets(player).isEmpty());
}
private boolean canFeed(Pony player) {
return player.asEntity().getHealth() < player.asEntity().getMaxHealth()
|| player.asEntity().canConsume(false);
}
private boolean canDrain(Entity e) {
return (e instanceof LivingEntity)
&& (e instanceof CowEntity
|| e instanceof MerchantEntity
|| e instanceof PlayerEntity
|| e instanceof SheepEntity
|| e instanceof PigEntity
|| e instanceof HostileEntity);
return Hit.of(ChangelingFeedingSpell.canFeed(player) && !getTargets(player).findAny().isEmpty());
}
@Override
@ -76,16 +64,6 @@ public class ChangelingFeedAbility implements Ability<Hit> {
return Hit.SERIALIZER;
}
protected List<LivingEntity> getTargets(Pony player) {
List<Entity> list = VecHelper.findInRange(player.asEntity(), player.asWorld(), player.getOriginVector(), 3, this::canDrain);
TraceHelper.<LivingEntity>findEntity(player.asEntity(), 17, 1,
looked -> looked instanceof LivingEntity && !list.contains(looked) && canDrain(looked))
.ifPresent(list::add);
return list.stream().map(i -> (LivingEntity)i).collect(Collectors.toList());
}
@Override
public double getCostEstimate(Pony player) {
return 0;
@ -93,7 +71,7 @@ public class ChangelingFeedAbility implements Ability<Hit> {
@Override
public boolean apply(Pony iplayer, Hit data) {
if (!canFeed(iplayer)) {
if (!ChangelingFeedingSpell.canFeed(iplayer)) {
return false;
}
@ -103,64 +81,25 @@ public class ChangelingFeedAbility implements Ability<Hit> {
int maximumFoodGain = player.canConsume(false) ? (20 - player.getHungerManager().getFoodLevel()) : 0;
if (maximumHealthGain > 0 || maximumFoodGain > 0) {
List<LivingEntity> targets = getTargets(iplayer).map(LivingEntity.class::cast).toList();
float healAmount = 0;
if (targets.size() > 0) {
new ChangelingFeedingSpell(targets, maximumHealthGain, maximumFoodGain).apply(iplayer);
for (LivingEntity i : getTargets(iplayer)) {
healAmount += drainFrom(iplayer, i);
}
int foodAmount = (int)Math.floor(Math.min(healAmount / 3, maximumFoodGain));
if (foodAmount > 0) {
healAmount -= foodAmount;
}
player.getHungerManager().add(Math.max(1, foodAmount), 0.125f);
player.heal(Math.max(1, Math.min(healAmount, maximumHealthGain)));
}
if (!canFeed(iplayer)) {
iplayer.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, (float)player.getWorld().random.nextTriangular(1F, 0.2F));
} else {
iplayer.playSound(USounds.ENTITY_PLAYER_CHANGELING_FEED, 0.1F, iplayer.getRandomPitch());
return true;
}
}
iplayer.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, (float)player.getWorld().random.nextTriangular(1F, 0.2F));
return true;
}
public float drainFrom(Pony changeling, LivingEntity living) {
DamageSource d = changeling.damageOf(UDamageTypes.LOVE_DRAINING, changeling);
float damage = living.getHealth()/2;
if (damage > 0) {
living.damage(d, damage);
}
ParticleUtils.spawnParticles(UParticles.CHANGELING_MAGIC, living, 7);
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, changeling.asEntity(), 0.2F), living, 1);
if (changeling.asEntity().hasStatusEffect(StatusEffects.NAUSEA)) {
StatusEffectInstance effect = changeling.asEntity().getStatusEffect(StatusEffects.NAUSEA);
changeling.asEntity().removeStatusEffect(StatusEffects.NAUSEA);
living.addStatusEffect(effect);
} else if (changeling.asWorld().random.nextInt(2300) == 0) {
living.addStatusEffect(new StatusEffectInstance(StatusEffects.WITHER, 20, 1));
}
if (living instanceof PlayerEntity) {
damage ++;
damage *= 1.6F;
if (!changeling.asEntity().hasStatusEffect(StatusEffects.HEALTH_BOOST)) {
changeling.asEntity().addStatusEffect(new StatusEffectInstance(StatusEffects.HEALTH_BOOST, 13000, 1));
}
}
return damage;
protected Stream<Entity> getTargets(Pony player) {
return Stream.concat(
VecHelper.findInRange(player.asEntity(), player.asWorld(), player.getOriginVector(), 3, TARGET_PREDICATE).stream(),
TraceHelper.findEntity(player.asEntity(), 17, 1, TARGET_PREDICATE).stream()
).distinct();
}
@Override

View file

@ -10,10 +10,10 @@ import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.data.Pos;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.TransformCropsRecipe;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.recipe.TransformCropsRecipe;
import com.minelittlepony.unicopia.recipe.URecipes;
import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
import com.minelittlepony.unicopia.util.TraceHelper;
import com.minelittlepony.unicopia.util.VecHelper;
@ -108,7 +108,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
}
}
if (w.getBlockState(pos).isIn(UTags.UNAFFECTED_BY_GROW_ABILITY)) {
if (w.getBlockState(pos).isIn(UTags.Blocks.UNAFFECTED_BY_GROW_ABILITY)) {
return 0;
}

View file

@ -162,7 +162,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
ParticleUtils.spawnParticle(player.getWorld(), UParticles.GROUND_POUND, player.getX(), player.getY() - 1, player.getZ(), 0, 0, 0);
BlockState steppingState = player.getSteppingBlockState();
if (steppingState.isIn(UTags.KICKS_UP_DUST)) {
if (steppingState.isIn(UTags.Blocks.KICKS_UP_DUST)) {
ParticleUtils.spawnParticle(player.getWorld(), new BlockStateParticleEffect(UParticles.DUST_CLOUD, steppingState), player.getBlockPos().down().toCenterPos(), Vec3d.ZERO);
}
@ -227,7 +227,7 @@ public class EarthPonyStompAbility implements Ability<Hit> {
w.syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state));
}
if (state.isIn(UTags.KICKS_UP_DUST)) {
if (state.isIn(UTags.Blocks.KICKS_UP_DUST)) {
if (w.random.nextInt(4) == 0 && w.isAir(pos.up()) && w.getFluidState(pos.up()).isEmpty()) {
ParticleUtils.spawnParticle(w, new BlockStateParticleEffect(UParticles.DUST_CLOUD, state), pos.up().toCenterPos(), VecHelper.supply(() -> w.random.nextTriangular(0, 0.1F)));
}

View file

@ -35,7 +35,7 @@ public class PegasusCaptureStormAbility implements Ability<Hit> {
@Override
public boolean canUse(Race race) {
return race.canInteractWithClouds();
return race.canInfluenceWeather();
}
@Nullable

View file

@ -28,7 +28,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
@Override
public boolean canUse(Race race) {
return race.canInteractWithClouds();
return race.canInfluenceWeather();
}
@Nullable

View file

@ -110,7 +110,7 @@ public class ScreechAbility implements Ability<Numeric> {
if (living.getWorld().random.nextInt(MOB_SPOOK_PROBABILITY) == 0) {
RegistryUtils.pickRandom(living.getWorld(), UTags.SPOOKED_MOB_DROPS).ifPresent(drop -> {
RegistryUtils.pickRandom(living.getWorld(), UTags.Items.SPOOKED_MOB_DROPS).ifPresent(drop -> {
living.dropStack(drop.getDefaultStack());
living.playSound(USounds.Vanilla.ENTITY_ITEM_PICKUP, 1, 0.1F);
UCriteria.SPOOK_MOB.trigger(player.asEntity());

View file

@ -27,6 +27,7 @@ import net.minecraft.sound.SoundCategory;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.World;
@ -89,8 +90,10 @@ public class UnicornTeleportAbility implements Ability<Pos> {
return trace.getBlockOrEntityPos().map(pos -> {
final BlockPos originalPos = pos;
Direction globalUp = player.getPhysics().isGravityNegative() ? Direction.DOWN : Direction.UP;
boolean originalPosHasSupport = exception(w, pos, player.asEntity());
boolean originalPosValid = enterable(w, pos.up()) && enterable(w, pos.up(2));
boolean originalPosValid = enterable(w, pos.offset(globalUp)) && enterable(w, pos.offset(globalUp, 2));
if (w.getBlockState(pos).isOf(Blocks.POWDER_SNOW) && !PowderSnowBlock.canWalkOnPowderSnow(player.asEntity())) {
return null;
@ -111,11 +114,11 @@ public class UnicornTeleportAbility implements Ability<Pos> {
if (pos.getX() != originalPos.getX() || pos.getZ() != originalPos.getZ()) {
// check support
int steps = 0;
while (enterable(w, pos.down())) {
pos = pos.down();
while (enterable(w, pos.offset(globalUp.getOpposite()))) {
pos = pos.offset(globalUp.getOpposite());
if (++steps > 2) {
if (originalPosValid) {
pos = originalPos.up();
pos = originalPos.offset(globalUp);
break;
} else {
return null;
@ -125,7 +128,7 @@ public class UnicornTeleportAbility implements Ability<Pos> {
}
if ((!enterable(w, pos) && exception(w, pos, player.asEntity()))
|| (!enterable(w, pos.up()) && exception(w, pos.up(), player.asEntity()))) {
|| (!enterable(w, pos.offset(globalUp)) && exception(w, pos.offset(globalUp), player.asEntity()))) {
return null;
}

View file

@ -14,12 +14,14 @@ import com.minelittlepony.unicopia.entity.damage.UDamageSources;
import com.minelittlepony.unicopia.particle.ParticleSource;
import com.minelittlepony.unicopia.server.world.Ether;
import com.minelittlepony.unicopia.server.world.ModificationType;
import com.minelittlepony.unicopia.server.world.OfflinePlayerCache;
import com.minelittlepony.unicopia.util.SoundEmitter;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameRules;
@ -67,10 +69,18 @@ public interface Caster<E extends Entity> extends
}
if (getMaster() instanceof PlayerEntity player) {
if (!asWorld().canPlayerModifyAt(player, pos)) {
if (!player.canModifyBlocks() || !asWorld().canPlayerModifyAt(player, pos)) {
return false;
}
} else {
if (asWorld() instanceof ServerWorld sw) {
@Nullable
PlayerEntity player = OfflinePlayerCache.getOfflinePlayer(sw, getMasterId().orElse(null));
if (player != null && !player.canModifyBlocks() || !sw.canPlayerModifyAt(player, pos)) {
return false;
}
}
if (!asWorld().getGameRules().getBoolean(GameRules.DO_MOB_GRIEFING)) {
return false;
}

View file

@ -0,0 +1,162 @@
package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.List;
import java.util.stream.Collectors;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.effect.AbstractSpell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.entity.EntityReference;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.util.math.MathHelper;
public class ChangelingFeedingSpell extends AbstractSpell {
private List<EntityReference<LivingEntity>> targets = List.of();
private int nextTargetIndex;
private float healthToDrain;
private int foodToDrain;
private float damageThisTick;
public ChangelingFeedingSpell(CustomisedSpellType<?> type) {
super(type);
setHidden(true);
}
public ChangelingFeedingSpell(List<LivingEntity> feedTarget, float healthToDrain, int foodToDrain) {
this(SpellType.FEED.withTraits());
this.targets = feedTarget.stream().map(EntityReference::new).collect(Collectors.toList() /* make mutable */);
this.healthToDrain = healthToDrain;
this.foodToDrain = foodToDrain;
}
@Override
public boolean tick(Caster<?> source, Situation situation) {
if (!(source instanceof Pony changeling) || situation != Situation.BODY || !source.canUse(Abilities.FEED)) {
return false;
}
PlayerEntity player = changeling.asEntity();
if (!canFeed(changeling)) {
changeling.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, (float)player.getWorld().random.nextTriangular(1F, 0.2F));
return false;
}
float tickDrain = Math.min(0.05F, healthToDrain);
damageThisTick += tickDrain;
if (damageThisTick > 1) {
damageThisTick--;
float healAmount = drain(changeling, 1);
float foodAmount = Math.min(healAmount / 3F, foodToDrain);
if (foodAmount > 0) {
healAmount -= foodAmount;
}
foodAmount = MathHelper.clamp(foodAmount, 0, foodToDrain);
healAmount = MathHelper.clamp(healAmount, 0, healthToDrain);
int shanks = MathHelper.floor(foodAmount);
player.getHungerManager().add(shanks, foodAmount - shanks);
player.heal(healAmount);
if (!canFeed(changeling)) {
changeling.playSound(USounds.Vanilla.ENTITY_PLAYER_BURP, 1, (float)player.getWorld().random.nextTriangular(1F, 0.2F));
} else {
changeling.playSound(USounds.ENTITY_PLAYER_CHANGELING_FEED, 0.1F, changeling.getRandomPitch());
}
foodToDrain -= foodAmount;
healthToDrain -= healAmount;
}
return !targets.isEmpty() && (healthToDrain > 0 || foodToDrain > 0);
}
private float drain(Pony changeling, float max) {
List<EntityReference<LivingEntity>> targets = this.targets;
while (!targets.isEmpty()) {
int index = MathHelper.clamp(nextTargetIndex, 0, targets.size());
LivingEntity l = targets.get(index).getOrEmpty(changeling.asWorld()).orElse(null);
if (l != null && !l.isRemoved() && l.distanceTo(changeling.asEntity()) < 4) {
nextTargetIndex = (nextTargetIndex + 1) % targets.size();
return drainFrom(changeling, l, max);
} else {
targets.remove(index);
}
}
return 0;
}
public float drainFrom(Pony changeling, LivingEntity living, float damage) {
DamageSource d = changeling.damageOf(UDamageTypes.LOVE_DRAINING, changeling);
if (damage > 0) {
living.damage(d, damage);
}
ParticleUtils.spawnParticles(UParticles.CHANGELING_MAGIC, living, 7);
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, changeling.asEntity(), 0.2F), living, 1);
if (changeling.asEntity().hasStatusEffect(StatusEffects.NAUSEA)) {
StatusEffectInstance effect = changeling.asEntity().getStatusEffect(StatusEffects.NAUSEA);
changeling.asEntity().removeStatusEffect(StatusEffects.NAUSEA);
living.addStatusEffect(effect);
} else if (changeling.asWorld().random.nextInt(2300) == 0) {
living.addStatusEffect(new StatusEffectInstance(StatusEffects.WITHER, 20, 1));
}
if (living instanceof PlayerEntity) {
damage ++;
damage *= 1.6F;
if (!changeling.asEntity().hasStatusEffect(StatusEffects.HEALTH_BOOST)) {
changeling.asEntity().addStatusEffect(new StatusEffectInstance(StatusEffects.HEALTH_BOOST, 13000, 1));
}
}
return damage;
}
public static boolean canFeed(Pony player) {
return player.asEntity().getHealth() < player.asEntity().getMaxHealth()
|| player.asEntity().canConsume(false);
}
@Override
public void toNBT(NbtCompound compound) {
super.toNBT(compound);
compound.putFloat("healthToDrain", healthToDrain);
compound.putInt("foodToDrain", foodToDrain);
compound.putFloat("damageThisTick", damageThisTick);
compound.put("targets", EntityReference.<LivingEntity>getSerializer().writeAll(targets));
}
@Override
public void fromNBT(NbtCompound compound) {
super.fromNBT(compound);
healthToDrain = compound.getFloat("healthToDrain");
foodToDrain = compound.getInt("foodToDrain");
damageThisTick = compound.getFloat("damageThisTick");
targets = compound.contains("targets", NbtElement.LIST_TYPE)
? EntityReference.<LivingEntity>getSerializer().readAll(compound.getList("targets", NbtElement.COMPOUND_TYPE)).toList()
: List.of();
}
}

View file

@ -64,7 +64,7 @@ public class RainboomAbilitySpell extends AbstractSpell {
});
EFFECT_RANGE.translate(source.getOrigin()).getBlockPositions().forEach(pos -> {
BlockState state = source.asWorld().getBlockState(pos);
if (state.isIn(UTags.FRAGILE) && source.canModifyAt(pos, ModificationType.PHYSICAL)) {
if (state.isIn(UTags.Blocks.FRAGILE) && source.canModifyAt(pos, ModificationType.PHYSICAL)) {
source.asWorld().breakBlock(pos, true);
}
});

View file

@ -12,6 +12,8 @@ import com.minelittlepony.unicopia.item.EnchantableItem;
import com.minelittlepony.unicopia.util.CodecUtils;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.recipe.Ingredient;
@ -36,6 +38,17 @@ public class IngredientWithSpell implements Predicate<ItemStack> {
private final Supplier<ItemStack[]> stacks;
public static IngredientWithSpell mundane(ItemConvertible item) {
return new IngredientWithSpell(Optional.of(Ingredient.ofItems(item)), Optional.empty());
}
public static IngredientWithSpell of(ItemConvertible base, SpellType<?> spell) {
if (spell == SpellType.EMPTY_KEY) {
return mundane(base);
}
return new IngredientWithSpell(Optional.of(Ingredient.ofItems(base)), Optional.of(spell));
}
private IngredientWithSpell(Optional<Ingredient> stack, Optional<SpellType<?>> spell) {
this.stack = stack;
this.spell = spell;

View file

@ -9,7 +9,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
import com.minelittlepony.unicopia.item.EnchantableItem;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.recipe.URecipes;
import com.minelittlepony.unicopia.util.CodecUtils;
import com.minelittlepony.unicopia.util.InventoryUtil;
import com.mojang.datafixers.util.Pair;
@ -47,7 +47,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
*/
final ItemStack output;
private SpellCraftingRecipe(IngredientWithSpell material, TraitIngredient requiredTraits, List<IngredientWithSpell> requiredItems, ItemStack output) {
public SpellCraftingRecipe(IngredientWithSpell material, TraitIngredient requiredTraits, List<IngredientWithSpell> requiredItems, ItemStack output) {
this.material = material;
this.requiredTraits = requiredTraits;
this.requiredItems = requiredItems;

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
import com.minelittlepony.unicopia.item.*;
import com.minelittlepony.unicopia.recipe.URecipes;
import com.minelittlepony.unicopia.util.InventoryUtil;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
@ -16,12 +17,10 @@ import net.minecraft.world.World;
/**
* A recipe for creating a new spell from input traits and items.
*/
public class SpellDuplicatingRecipe implements SpellbookRecipe {
final IngredientWithSpell material;
private SpellDuplicatingRecipe(IngredientWithSpell material) {
this.material = material;
}
public record SpellDuplicatingRecipe (IngredientWithSpell material) implements SpellbookRecipe {
public static final Codec<SpellDuplicatingRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
IngredientWithSpell.CODEC.fieldOf("material").forGetter(recipe -> recipe.material)
).apply(instance, SpellDuplicatingRecipe::new));
@Override
public void buildCraftingTree(CraftingTreeBuilder builder) {
@ -81,10 +80,6 @@ public class SpellDuplicatingRecipe implements SpellbookRecipe {
}
public static class Serializer implements RecipeSerializer<SpellDuplicatingRecipe> {
private static final Codec<SpellDuplicatingRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
IngredientWithSpell.CODEC.fieldOf("material").forGetter(recipe -> recipe.material)
).apply(instance, SpellDuplicatingRecipe::new));
@Override
public Codec<SpellDuplicatingRecipe> codec() {
return CODEC;

View file

@ -5,6 +5,7 @@ import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
import com.minelittlepony.unicopia.item.*;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.minelittlepony.unicopia.recipe.URecipes;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
@ -15,12 +16,10 @@ import net.minecraft.world.World;
/**
* Recipe for adding traits to an existing spell.
*/
public class SpellEnhancingRecipe implements SpellbookRecipe {
final IngredientWithSpell material;
private SpellEnhancingRecipe(IngredientWithSpell material) {
this.material = material;
}
public record SpellEnhancingRecipe (IngredientWithSpell material) implements SpellbookRecipe {
public static final Codec<SpellEnhancingRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
IngredientWithSpell.CODEC.fieldOf("material").forGetter(recipe -> recipe.material)
).apply(instance, SpellEnhancingRecipe::new));
public IngredientWithSpell getBaseMaterial() {
return material;
@ -65,10 +64,6 @@ public class SpellEnhancingRecipe implements SpellbookRecipe {
}
public static class Serializer implements RecipeSerializer<SpellEnhancingRecipe> {
private static final Codec<SpellEnhancingRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
IngredientWithSpell.CODEC.fieldOf("material").forGetter(recipe -> recipe.material)
).apply(instance, SpellEnhancingRecipe::new));
@Override
public Codec<SpellEnhancingRecipe> codec() {
return CODEC;
@ -81,7 +76,7 @@ public class SpellEnhancingRecipe implements SpellbookRecipe {
@Override
public void write(PacketByteBuf buf, SpellEnhancingRecipe recipe) {
recipe.material.write(buf);
recipe.material().write(buf);
}
}
}

View file

@ -1,7 +1,7 @@
package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import com.minelittlepony.unicopia.item.EnchantableItem;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.recipe.URecipes;
import com.minelittlepony.unicopia.util.InventoryUtil;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;

View file

@ -5,7 +5,7 @@ import java.util.List;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.recipe.URecipes;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Recipe;

View file

@ -16,22 +16,36 @@ public record TraitIngredient (
Optional<SpellTraits> min,
Optional<SpellTraits> max
) implements Predicate<SpellTraits> {
public static final Codec<TraitIngredient> CODEC = Codecs.xor(
SpellTraits.CODEC.flatXmap(
traits -> DataResult.success(new TraitIngredient(Optional.ofNullable(traits), Optional.empty())),
ingredient -> ingredient.min().map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Cannot serialize an empty trait ingredient"))),
RecordCodecBuilder.<TraitIngredient>create(instance -> instance.group(
public static final TraitIngredient EMPTY = new TraitIngredient(Optional.empty(), Optional.empty());
private static final Codec<TraitIngredient> INLINE_CODEC = SpellTraits.CODEC.xmap(
traits -> new TraitIngredient(Optional.ofNullable(traits), Optional.empty()),
ingredient -> ingredient.min().orElse(SpellTraits.EMPTY));
private static final Codec<TraitIngredient> STRUCTURED_CODEC = RecordCodecBuilder.<TraitIngredient>create(instance -> instance.group(
SpellTraits.CODEC.optionalFieldOf("min").forGetter(TraitIngredient::min),
SpellTraits.CODEC.optionalFieldOf("max").forGetter(TraitIngredient::max)
).apply(instance, TraitIngredient::new)).flatXmap(
ingredient -> !ingredient.isEmpty() ? DataResult.success(ingredient) : DataResult.error(() -> "No min or max supplied for ingredient"),
ingredient -> DataResult.success(ingredient)
)
).flatXmap(
).apply(instance, TraitIngredient::new));
public static final Codec<TraitIngredient> CODEC = Codecs.xor(INLINE_CODEC, STRUCTURED_CODEC).flatXmap(
either -> either.left().or(either::right).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Invalid traits")),
ingredient -> DataResult.success(ingredient.max.isEmpty() ? Either.left(ingredient) : Either.right(ingredient))
);
public static TraitIngredient of(SpellTraits minTraits) {
if (minTraits.isEmpty()) {
return EMPTY;
}
return new TraitIngredient(Optional.of(minTraits), Optional.empty());
}
public static TraitIngredient of(SpellTraits minTraits, SpellTraits maxTraits) {
if (minTraits.isEmpty() && maxTraits.isEmpty()) {
return EMPTY;
}
return new TraitIngredient(
Optional.of(minTraits).filter(s -> !s.isEmpty()),
Optional.of(maxTraits).filter(s -> !s.isEmpty())
);
}
public boolean isEmpty() {
return min.filter(SpellTraits::isPresent).isEmpty()
&& max.filter(SpellTraits::isPresent).isEmpty();

View file

@ -86,7 +86,7 @@ public class CatapultSpell extends AbstractSpell implements ProjectileDelegate.B
}
BlockState state = world.getBlockState(bpos);
if (state.isIn(UTags.CATAPULT_IMMUNE)) {
if (state.isIn(UTags.Blocks.CATAPULT_IMMUNE)) {
return;
}

View file

@ -61,7 +61,9 @@ public class HydrophobicSpell extends AbstractSpell {
storedFluidPositions.removeIf(entry -> {
if (!area.isPointInside(Vec3d.ofCenter(entry.pos()))) {
if (source.canModifyAt(entry.pos())) {
entry.restore(world);
}
return true;
}
@ -72,7 +74,7 @@ public class HydrophobicSpell extends AbstractSpell {
pos = new BlockPos(pos);
BlockState state = world.getBlockState(pos);
if (state.getFluidState().isIn(affectedFluid)) {
if (source.canModifyAt(pos) && state.getFluidState().isIn(affectedFluid)) {
Block block = state.getBlock();
if (block instanceof FluidBlock) {
@ -95,7 +97,7 @@ public class HydrophobicSpell extends AbstractSpell {
source.spawnParticles(new Sphere(true, range), 10, pos -> {
BlockPos bp = BlockPos.ofFloored(pos);
if (source.asWorld().getFluidState(bp.up()).isIn(affectedFluid)) {
if (source.canModifyAt(bp) && source.asWorld().getFluidState(bp.up()).isIn(affectedFluid)) {
source.addParticle(UParticles.RAIN_DROPS, pos, Vec3d.ZERO);
}
});
@ -116,7 +118,9 @@ public class HydrophobicSpell extends AbstractSpell {
protected void onDestroyed(Caster<?> caster) {
Ether.get(caster.asWorld()).remove(this, caster);
storedFluidPositions.removeIf(entry -> {
if (caster.canModifyAt(entry.pos())) {
entry.restore(caster.asWorld());
}
return true;
});
}

View file

@ -48,8 +48,9 @@ public class InfernoSpell extends FireSpell {
for (int i = 0; i < radius * 2; i++) {
if (w.random.nextInt(12) == 0) {
Vec3d vec = shape.computePoint(w.random).add(origin);
BlockPos pos = BlockPos.ofFloored(vec);
if (!applyBlocks(w, BlockPos.ofFloored(vec))) {
if (source.canModifyAt(pos) && !applyBlocks(w, pos)) {
applyEntities(source, vec);
}
}

View file

@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.ability.magic.spell.ChangelingFeedingSpell;
import com.minelittlepony.unicopia.ability.magic.spell.DispersableDisguiseSpell;
import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell;
import com.minelittlepony.unicopia.ability.magic.spell.PlaceableSpell;
@ -49,6 +50,7 @@ public final class SpellType<T extends Spell> implements Affine, SpellPredicate<
public static final SpellType<ThrowableSpell> THROWN_SPELL = register("thrown", Affinity.NEUTRAL, 0, false, SpellTraits.EMPTY, ThrowableSpell::new);
public static final SpellType<DispersableDisguiseSpell> CHANGELING_DISGUISE = register("disguise", Affinity.BAD, 0x19E48E, false, SpellTraits.EMPTY, DispersableDisguiseSpell::new);
public static final SpellType<ChangelingFeedingSpell> FEED = register("feed", Affinity.BAD, 0xBDBDF9, false, SpellTraits.EMPTY, ChangelingFeedingSpell::new);
public static final SpellType<RainboomAbilitySpell> RAINBOOM = register("rainboom", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RainboomAbilitySpell::new);
public static final SpellType<RageAbilitySpell> RAGE = register("rage", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, RageAbilitySpell::new);
public static final SpellType<TimeControlAbilitySpell> TIME_CONTROL = register("time_control", Affinity.GOOD, 0xBDBDF9, false, SpellTraits.EMPTY, TimeControlAbilitySpell::new);

View file

@ -66,7 +66,7 @@ public class TransformationSpell extends AbstractSpell implements ProjectileDele
@SuppressWarnings("unchecked")
private <T extends MobEntity> Optional<EntityType<T>> pickType(EntityType<?> except, World world) {
Set<EntityType<?>> options = RegistryUtils.valuesForTag(world, UTags.TRANSFORMABLE_ENTITIES).collect(Collectors.toSet());
Set<EntityType<?>> options = RegistryUtils.valuesForTag(world, UTags.Entities.TRANSFORMABLE).collect(Collectors.toSet());
if (except.getSpawnGroup() == SpawnGroup.MONSTER) {
options.removeIf(t -> t.getSpawnGroup() == SpawnGroup.MONSTER);
} else {

View file

@ -7,10 +7,7 @@ import java.util.stream.Stream;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.command.CommandArgumentEnum;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.command.argument.EnumArgumentType;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@ -20,7 +17,6 @@ import net.minecraft.text.*;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.StringIdentifiable;
import net.minecraft.util.dynamic.Codecs;
public enum Trait implements CommandArgumentEnum<Trait> {
/**
@ -64,14 +60,10 @@ public enum Trait implements CommandArgumentEnum<Trait> {
BLOOD(TraitGroup.DARKNESS);
private static final Map<Identifier, Trait> IDS = Arrays.stream(values()).collect(Collectors.toMap(Trait::getId, Function.identity()));
@Deprecated
private static final EnumCodec<Trait> NAME_CODEC = StringIdentifiable.createCodec(Trait::values, String::toLowerCase);
@Deprecated
private static final EnumCodec<Trait> ID_CODEC = StringIdentifiable.createCodec(Trait::values, i -> "unicopia:" + i);
public static final Codec<Trait> CODEC = Codecs.xor(NAME_CODEC, ID_CODEC).flatXmap(
either -> either.left().or(either::right).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Not a proper trait")),
trait -> DataResult.success(Either.right(trait))
public static final EnumCodec<Trait> CODEC = StringIdentifiable.createCodec(Trait::values, n -> n.toLowerCase(Locale.ROOT));
public static final Codec<Set<Trait>> SET_CODEC = CODEC.listOf().xmap(
l -> l.stream().distinct().collect(Collectors.toSet()),
s -> s.stream().toList()
);
private final Identifier id;
@ -115,7 +107,7 @@ public enum Trait implements CommandArgumentEnum<Trait> {
@Override
public String asString() {
return name();
return getId().getPath();
}
public TraitGroup getGroup() {
@ -173,7 +165,7 @@ public enum Trait implements CommandArgumentEnum<Trait> {
@Deprecated
public static Optional<Trait> fromName(String name) {
return Optional.ofNullable(NAME_CODEC.byId(name));
return Optional.ofNullable(CODEC.byId(name));
}
public static EnumArgumentType<Trait> argument() {

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell.trait;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -10,6 +11,7 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgMarkTraitRead;
@ -76,9 +78,12 @@ public class TraitDiscovery implements NbtSerialisable, Copyable<TraitDiscovery>
});
unreadTraits.addAll(newTraits);
pony.setDirty();
if (!newTraits.isEmpty() && !pony.asWorld().isClient) {
if (!newTraits.isEmpty()) {
if (!pony.asWorld().isClient) {
Channel.UNLOCK_TRAITS.sendToPlayer(new MsgUnlockTraits(newTraits), (ServerPlayerEntity)pony.asEntity());
}
UCriteria.TRAIT_DISCOVERED.trigger(pony.asEntity());
}
}
public SpellTraits getKnownTraits(Item item) {
@ -103,6 +108,10 @@ public class TraitDiscovery implements NbtSerialisable, Copyable<TraitDiscovery>
return traits.contains(trait);
}
public boolean isKnown(Collection<Trait> traits) {
return traits.containsAll(traits);
}
@Environment(EnvType.CLIENT)
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip) {
SpellTraits.getEmbeddedTraits(stack)

View file

@ -10,6 +10,7 @@ import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.fabricmc.fabric.api.util.TriState;
import net.minecraft.advancement.AdvancementCriterion;
import net.minecraft.advancement.criterion.AbstractCriterion;
import net.minecraft.entity.Entity;
import net.minecraft.predicate.entity.EntityPredicate;
@ -37,6 +38,22 @@ public class CustomEventCriterion extends AbstractCriterion<CustomEventCriterion
void trigger(@Nullable Entity player);
}
public static AdvancementCriterion<?> create(String name) {
return UCriteria.CUSTOM_EVENT.create(new Conditions(Optional.empty(), name, RacePredicate.EMPTY, TriState.DEFAULT, 1));
}
public static AdvancementCriterion<?> create(String name, int count) {
return UCriteria.CUSTOM_EVENT.create(new Conditions(Optional.empty(), name, RacePredicate.EMPTY, TriState.DEFAULT, count));
}
public static AdvancementCriterion<?> createFlying(String name) {
return UCriteria.CUSTOM_EVENT.create(new Conditions(Optional.empty(), name, RacePredicate.EMPTY, TriState.TRUE, 1));
}
public static AdvancementCriterion<?> createFlying(String name, int count) {
return UCriteria.CUSTOM_EVENT.create(new Conditions(Optional.empty(), name, RacePredicate.EMPTY, TriState.TRUE, count));
}
public record Conditions (
Optional<LootContextPredicate> player,
String event,

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.advancement;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import com.minelittlepony.unicopia.Race;
@ -10,17 +11,21 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.server.network.ServerPlayerEntity;
public record RacePredicate(Set<Race> include, Set<Race> exclude) implements Predicate<ServerPlayerEntity> {
public static final RacePredicate EMPTY = new RacePredicate(Set.of(), Set.of());
public record RacePredicate(Optional<Set<Race>> include, Optional<Set<Race>> exclude) implements Predicate<ServerPlayerEntity> {
public static final RacePredicate EMPTY = new RacePredicate(Optional.empty(), Optional.empty());
private static final Codec<Set<Race>> RACE_SET_CODEC = CodecUtils.setOf(Race.REGISTRY.getCodec());
private static final Codec<RacePredicate> BASE_CODEC = RecordCodecBuilder.create(instance -> instance.group(
RACE_SET_CODEC.fieldOf("include").forGetter(RacePredicate::include),
RACE_SET_CODEC.fieldOf("exclude").forGetter(RacePredicate::exclude)
RACE_SET_CODEC.optionalFieldOf("include").forGetter(RacePredicate::include),
RACE_SET_CODEC.optionalFieldOf("exclude").forGetter(RacePredicate::exclude)
).apply(instance, RacePredicate::of));
public static final Codec<RacePredicate> CODEC = CodecUtils.xor(BASE_CODEC, RACE_SET_CODEC.xmap(include -> of(include, Set.of()), RacePredicate::include));
public static final Codec<RacePredicate> CODEC = CodecUtils.xor(BASE_CODEC, RACE_SET_CODEC.xmap(include -> of(Optional.of(include), Optional.empty()), a -> a.include().orElse(Set.of())));
private static RacePredicate of(Set<Race> include, Set<Race> exclude) {
public static RacePredicate of(Set<Race> include, Set<Race> exclude) {
return of(Optional.of(include).filter(s -> !s.isEmpty()), Optional.of(exclude).filter(s -> !s.isEmpty()));
}
public static RacePredicate of(Optional<Set<Race>> include, Optional<Set<Race>> exclude) {
if (include.isEmpty() && exclude.isEmpty()) {
return EMPTY;
}
@ -30,6 +35,10 @@ public record RacePredicate(Set<Race> include, Set<Race> exclude) implements Pre
@Override
public boolean test(ServerPlayerEntity player) {
Race race = Pony.of(player).getSpecies();
return (include.isEmpty() || include.contains(race)) && !(!exclude.isEmpty() && exclude.contains(race));
return (include.isEmpty() || include.get().contains(race)) && !(!exclude.isEmpty() && exclude.get().contains(race));
}
public boolean isEmpty() {
return include.isEmpty() && exclude.isEmpty();
}
}

View file

@ -0,0 +1,45 @@
package com.minelittlepony.unicopia.advancement;
import java.util.Optional;
import java.util.Set;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.advancement.AdvancementCriterion;
import net.minecraft.advancement.criterion.AbstractCriterion;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.predicate.entity.EntityPredicate;
import net.minecraft.predicate.entity.LootContextPredicate;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.dynamic.Codecs;
public class TraitDiscoveredCriterion extends AbstractCriterion<TraitDiscoveredCriterion.Conditions> {
@Override
public Codec<Conditions> getConditionsCodec() {
return Conditions.CODEC;
}
public static AdvancementCriterion<?> create(Set<Trait> traits) {
return UCriteria.TRAIT_DISCOVERED.create(new Conditions(Optional.empty(), traits));
}
public void trigger(PlayerEntity player) {
if (player instanceof ServerPlayerEntity) {
trigger((ServerPlayerEntity)player, c -> c.test((ServerPlayerEntity)player));
}
}
public record Conditions(Optional<LootContextPredicate> player, Set<Trait> traits) implements AbstractCriterion.Conditions {
public static final Codec<Conditions> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codecs.createStrictOptionalFieldCodec(EntityPredicate.LOOT_CONTEXT_PREDICATE_CODEC, "player").forGetter(Conditions::player),
Trait.SET_CODEC.fieldOf("traits").forGetter(Conditions::traits)
).apply(instance, Conditions::new));
public boolean test(ServerPlayerEntity player) {
return Pony.of(player).getDiscoveries().isKnown(traits);
}
}
}

View file

@ -6,6 +6,7 @@ public interface UCriteria {
CustomEventCriterion CUSTOM_EVENT = Criteria.register("unicopia:custom", new CustomEventCriterion());
RaceChangeCriterion PLAYER_CHANGE_RACE = Criteria.register("unicopia:player_change_race", new RaceChangeCriterion());
SendViaDragonBreathScrollCriterion SEND_DRAGON_BREATH = Criteria.register("unicopia:send_dragon_breath", new SendViaDragonBreathScrollCriterion());
TraitDiscoveredCriterion TRAIT_DISCOVERED = Criteria.register("unicopia:trait_discovered", new TraitDiscoveredCriterion());
CustomEventCriterion.Trigger LOOK_INTO_SUN = CUSTOM_EVENT.createTrigger("look_into_sun");
CustomEventCriterion.Trigger WEAR_SHADES = CUSTOM_EVENT.createTrigger("wear_shades");
@ -27,7 +28,9 @@ public interface UCriteria {
CustomEventCriterion.Trigger POWER_UP_HEART = CUSTOM_EVENT.createTrigger("power_up_heart");
CustomEventCriterion.Trigger SPLIT_SEA = CUSTOM_EVENT.createTrigger("split_sea");
CustomEventCriterion.Trigger RIDE_BALLOON = CUSTOM_EVENT.createTrigger("ride_balloon");
CustomEventCriterion.Trigger CONSTRUCT_BALLOON = CUSTOM_EVENT.createTrigger("construct_balloon");
CustomEventCriterion.Trigger TELEPORT_ABOVE_WORLD = CUSTOM_EVENT.createTrigger("teleport_above_world");
CustomEventCriterion.Trigger SEAPONY_TRANSITION = CUSTOM_EVENT.createTrigger("seapony_transition");
static void bootstrap() { }
}

View file

@ -9,7 +9,7 @@ import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
public class EnchantedFruitBlock extends FruitBlock {
static final BooleanProperty ENCHANTED = BooleanProperty.of("enchanted");
public static final BooleanProperty ENCHANTED = BooleanProperty.of("enchanted");
private static final MapCodec<EnchantedFruitBlock> CODEC = createCodec(EnchantedFruitBlock::new);

View file

@ -20,8 +20,11 @@ import net.minecraft.block.entity.BedBlockEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.enums.BedPart;
import net.minecraft.entity.mob.PiglinBrain;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.DyeColor;
import net.minecraft.util.StringIdentifiable;
@ -31,6 +34,7 @@ import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.event.GameEvent;
public class FancyBedBlock extends BedBlock {
public static final MapCodec<FancyBedBlock> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
@ -70,6 +74,45 @@ public class FancyBedBlock extends BedBlock {
return SHAPES.get(state.get(PART).ordinal()).apply(BedBlock.getOppositePartDirection(state));
}
@Deprecated
@Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
if (state.hasBlockEntity() && !state.isOf(newState.getBlock()) && state.get(PART) == BedPart.HEAD) {
world.getBlockEntity(pos, UBlockEntities.FANCY_BED).ifPresent(tile -> {
SheetPattern pattern = tile.getPattern();
if (pattern != SheetPattern.NONE) {
dropStack(world, pos, BedsheetsItem.forPattern(pattern).getDefaultStack());
}
});
}
super.onStateReplaced(state, world, pos, newState, moved);
}
@Override
public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
// MC-269785
BedPart part = state.get(PART);
BlockPos otherHalfPos = pos.offset(getDirectionTowardsOtherPart(part, state.get(FACING)));
BlockState otherHalfState = world.getBlockState(otherHalfPos);
if (/*!world.isClient &&*/ player.isCreative() && part == BedPart.FOOT && otherHalfState.isOf(this) && otherHalfState.get(PART) == BedPart.HEAD) {
if (!world.isClient) {
world.setBlockState(otherHalfPos, otherHalfState.getFluidState().getBlockState(), Block.NOTIFY_ALL | Block.SKIP_DROPS);
}
spawnBreakParticles(world, player, otherHalfPos, otherHalfState);
if (state.isIn(BlockTags.GUARDED_BY_PIGLINS)) {
PiglinBrain.onGuardedBlockInteracted(player, false);
}
world.emitGameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Emitter.of(player, state));
} else {
spawnBreakParticles(world, player, pos, state);
if (state.isIn(BlockTags.GUARDED_BY_PIGLINS)) {
PiglinBrain.onGuardedBlockInteracted(player, false);
}
world.emitGameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Emitter.of(player, state));
}
return state;
}
@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new Tile(pos, state);
@ -140,6 +183,7 @@ public class FancyBedBlock extends BedBlock {
public enum SheetPattern implements StringIdentifiable {
NONE(DyeColor.WHITE),
WHITE(DyeColor.WHITE),
LIGHT_GRAY(DyeColor.LIGHT_GRAY),
GRAY(DyeColor.GRAY),
BLACK(DyeColor.BLACK),

View file

@ -0,0 +1,208 @@
package com.minelittlepony.unicopia.block;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.block.jar.EntityJarContents;
import com.minelittlepony.unicopia.block.jar.FluidOnlyJarContents;
import com.minelittlepony.unicopia.block.jar.ItemsJarContents;
import com.mojang.serialization.MapCodec;
import com.minelittlepony.unicopia.block.jar.FakeFluidJarContents;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.InventoryProvider;
import net.minecraft.block.TransparentBlock;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsage;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
public class ItemJarBlock extends JarBlock implements BlockEntityProvider, InventoryProvider {
public static final MapCodec<ItemJarBlock> CODEC = createCodec(ItemJarBlock::new);
public ItemJarBlock(Settings settings) {
super(settings);
}
@Override
protected MapCodec<? extends TransparentBlock> getCodec() {
return CODEC;
}
@Override
public BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.MODEL;
}
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (hand == Hand.OFF_HAND) {
return ActionResult.PASS;
}
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(data -> data.interact(player, hand)).orElse(ActionResult.PASS);
}
@Deprecated
@Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
if (!moved && !state.isOf(newState.getBlock())) {
world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).ifPresent(data -> {
data.getContents().onDestroyed();
});
}
super.onStateReplaced(state, world, pos, newState, moved);
}
@Override
public boolean hasComparatorOutput(BlockState state) {
return true;
}
@Override
public int getComparatorOutput(BlockState state, World world, BlockPos pos) {
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR)
.map(TileData::getItems)
.map(data -> Math.min(16, data.stacks().size()))
.orElse(0);
}
@Deprecated
@Override
public boolean onSyncedBlockEvent(BlockState state, World world, BlockPos pos, int type, int data) {
super.onSyncedBlockEvent(state, world, pos, type, data);
BlockEntity blockEntity = world.getBlockEntity(pos);
return blockEntity != null && blockEntity.onSyncedBlockEvent(type, data);
}
@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new TileData(pos, state);
}
@Nullable
@Override
public SidedInventory getInventory(BlockState state, WorldAccess world, BlockPos pos) {
return world.getBlockEntity(pos, UBlockEntities.ITEM_JAR).map(TileData::getItems).orElse(null);
}
public static class TileData extends BlockEntity {
private JarContents contents = new ItemsJarContents(this);
public TileData(BlockPos pos, BlockState state) {
super(UBlockEntities.ITEM_JAR, pos, state);
}
public ActionResult interact(PlayerEntity player, Hand hand) {
TypedActionResult<JarContents> result = contents.interact(player, hand);
contents = result.getValue();
return result.getResult();
}
public JarContents getContents() {
return contents;
}
@Nullable
public ItemsJarContents getItems() {
return getContents() instanceof ItemsJarContents c ? c : null;
}
@Nullable
public EntityJarContents getEntity() {
return getContents() instanceof EntityJarContents c ? c : null;
}
@Nullable
public FluidJarContents getFluid() {
return getContents() instanceof FluidJarContents c ? c : null;
}
@Nullable
public FakeFluidJarContents getFakeFluid() {
return getContents() instanceof FakeFluidJarContents c ? c : null;
}
@Override
public Packet<ClientPlayPacketListener> toUpdatePacket() {
return BlockEntityUpdateS2CPacket.create(this);
}
@Override
public NbtCompound toInitialChunkDataNbt() {
return createNbt();
}
@Override
public void markDirty() {
super.markDirty();
if (getWorld() instanceof ServerWorld sw) {
sw.getChunkManager().markForUpdate(getPos());
}
}
@Override
public void readNbt(NbtCompound nbt) {
if (nbt.contains("items", NbtElement.COMPOUND_TYPE)) {
contents = new ItemsJarContents(this, nbt.getCompound("items"));
} else if (nbt.contains("entity", NbtElement.COMPOUND_TYPE)) {
contents = new EntityJarContents(this, nbt.getCompound("entity"));
} else if (nbt.contains("fluid", NbtElement.COMPOUND_TYPE)) {
contents = new FluidOnlyJarContents(this, nbt.getCompound("fluid"));
} else if (nbt.contains("fakeFluid", NbtElement.COMPOUND_TYPE)) {
contents = new FakeFluidJarContents(this, nbt.getCompound("fakeFluid"));
}
}
@Override
protected void writeNbt(NbtCompound nbt) {
var items = getItems();
if (items != null) {
nbt.put("items", items.toNBT(new NbtCompound()));
} else if (getEntity() != null) {
nbt.put("entity", getEntity().toNBT(new NbtCompound()));
} else if (getFluid() != null) {
nbt.put("fluid", getFluid().toNBT(new NbtCompound()));
} else if (getFakeFluid() != null) {
nbt.put("fakeFluid", getFakeFluid().toNBT(new NbtCompound()));
}
}
}
public interface JarContents {
TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand);
void onDestroyed();
NbtCompound toNBT(NbtCompound compound);
default void consumeAndSwap(PlayerEntity player, Hand hand, ItemStack output) {
player.setStackInHand(hand, ItemUsage.exchangeStack(player.getStackInHand(hand), player, output.copy()));
}
}
public interface FluidJarContents extends JarContents {
FluidVariant fluid();
default long amount() {
return FluidConstants.BUCKET;
}
}
}

View file

@ -0,0 +1,116 @@
package com.minelittlepony.unicopia.block;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.item.WeatherJarItem;
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
import com.mojang.serialization.MapCodec;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.ShapeContext;
import net.minecraft.block.TransparentBlock;
import net.minecraft.block.Waterloggable;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.explosion.Explosion;
public class JarBlock extends TransparentBlock implements Waterloggable {
public static final MapCodec<JarBlock> CODEC = createCodec(JarBlock::new);
private static final VoxelShape SHAPE = VoxelShapes.union(
Block.createCuboidShape(4, 0, 4, 12, 12, 12),
Block.createCuboidShape(6, 12, 6, 10, 16, 10),
Block.createCuboidShape(5, 13, 5, 11, 14, 11)
);
private static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED;
public JarBlock(Settings settings) {
super(settings);
setDefaultState(getDefaultState().with(WATERLOGGED, false));
}
@Override
protected MapCodec<? extends TransparentBlock> getCodec() {
return CODEC;
}
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(WATERLOGGED);
}
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return SHAPE;
}
@Deprecated
@Override
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
if (state.get(WATERLOGGED)) {
world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
}
return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos);
}
@Nullable
@Override
public BlockState getPlacementState(ItemPlacementContext ctx) {
return getDefaultState().with(WATERLOGGED, ctx.getWorld().getFluidState(ctx.getBlockPos()).getFluid() == Fluids.WATER);
}
@Deprecated
@Override
public FluidState getFluidState(BlockState state) {
return state.get(WATERLOGGED) ? Fluids.WATER.getStill(false) : super.getFluidState(state);
}
@Override
public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) {
if (this == UBlocks.LIGHTNING_JAR) {
world.addParticle(new LightningBoltParticleEffect(true, 10, 1, 0.6F, Optional.empty()), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 0, 0, 0);
}
}
@Deprecated
@Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
super.onStateReplaced(state, world, pos, newState, moved);
}
@Override
public void onDestroyedByExplosion(World world, BlockPos pos, Explosion explosion) {
if (asItem() instanceof WeatherJarItem jar) {
jar.releaseContents(world, pos);
}
}
@Override
public void afterBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack tool) {
super.afterBreak(world, player, pos, state, blockEntity, tool);
if (!EnchantmentHelper.hasSilkTouch(tool) && !player.shouldCancelInteraction()) {
if (asItem() instanceof WeatherJarItem jar) {
jar.releaseContents(world, pos);
}
}
}
}

View file

@ -85,7 +85,7 @@ public class PieBlock extends Block implements Waterloggable {
if (world.isClient) {
if (itemStack.isIn(UTags.CAN_CUT_PIE)) {
if (itemStack.isIn(UTags.Items.CAN_CUT_PIE)) {
return ActionResult.SUCCESS;
}
@ -98,7 +98,7 @@ public class PieBlock extends Block implements Waterloggable {
}
}
if (itemStack.isIn(UTags.CAN_CUT_PIE)) {
if (itemStack.isIn(UTags.Items.CAN_CUT_PIE)) {
SoundEmitter.playSoundAt(player, USounds.BLOCK_PIE_SLICE, SoundCategory.NEUTRAL, 1, 1);
removeSlice(world, pos, state, player);
itemStack.damage(1, player, p -> p.sendToolBreakStatus(hand));

View file

@ -47,7 +47,7 @@ public class PineappleCropBlock extends CropBlock {
}
@Override
protected boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
public boolean canPlantOnTop(BlockState floor, BlockView world, BlockPos pos) {
return floor.isOf(this) || super.canPlantOnTop(floor, world, pos);
}

View file

@ -119,7 +119,7 @@ public class SegmentedCropBlock extends CropBlock implements SegmentedBlock {
}
@Override
protected boolean canPlantOnTop(BlockState state, BlockView view, BlockPos pos) {
public boolean canPlantOnTop(BlockState state, BlockView view, BlockPos pos) {
return (state.getBlock() instanceof SegmentedCropBlock o && o.canSupportBlock(this, state, view, pos)) || super.canPlantOnTop(state, view, pos);
}
@ -226,4 +226,8 @@ public class SegmentedCropBlock extends CropBlock implements SegmentedBlock {
return state.getBlock() == this || (nextSegmentSupplier != null && nextSegmentSupplier.get().isNext(state));
}
@Nullable
public SegmentedCropBlock getNext() {
return nextSegmentSupplier == null ? null : nextSegmentSupplier.get();
}
}

View file

@ -208,7 +208,7 @@ public class SlimePustuleBlock extends Block {
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
super.onStateReplaced(state, world, pos, newState, moved);
if (state.isOf(this) && newState.isOf(this) && state.get(POWERED) != newState.get(POWERED)) {
world.updateNeighbor(pos.up(), this, pos);
world.updateNeighborsAlways(pos.up(), this);
}
}

View file

@ -15,6 +15,7 @@ public interface UBlockEntities {
BlockEntityType<CloudBedBlock.Tile> FANCY_BED = create("fancy_bed", BlockEntityType.Builder.create(CloudBedBlock.Tile::new, UBlocks.CLOTH_BED, UBlocks.CLOUD_BED));
BlockEntityType<ChestBlockEntity> CLOUD_CHEST = create("cloud_chest", BlockEntityType.Builder.create(CloudChestBlock.TileData::new, UBlocks.CLOUD_CHEST));
BlockEntityType<HiveBlock.TileData> HIVE_STORAGE = create("hive_storage", BlockEntityType.Builder.create(HiveBlock.TileData::new, UBlocks.HIVE));
BlockEntityType<ItemJarBlock.TileData> ITEM_JAR = create("item_jar", BlockEntityType.Builder.create(ItemJarBlock.TileData::new, UBlocks.JAR));
static <T extends BlockEntity> BlockEntityType<T> create(String id, Builder<T> builder) {
return Registry.register(Registries.BLOCK_ENTITY_TYPE, id, builder.build(null));

View file

@ -36,6 +36,7 @@ import com.minelittlepony.unicopia.item.cloud.CloudBlockItem;
import com.minelittlepony.unicopia.item.group.ItemGroupRegistry;
import com.minelittlepony.unicopia.server.world.UTreeGen;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.registry.CompostingChanceRegistry;
import net.fabricmc.fabric.api.registry.FlammableBlockRegistry;
import net.fabricmc.fabric.api.registry.OxidizableBlocksRegistry;
import net.fabricmc.fabric.api.registry.StrippableBlockRegistry;
@ -47,6 +48,7 @@ import net.minecraft.block.enums.Instrument;
import net.minecraft.block.piston.PistonBehavior;
import net.minecraft.item.*;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.util.ColorCode;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShapes;
@ -250,7 +252,13 @@ public interface UBlocks {
Block CLOUD_DOOR = register("cloud_door", new CloudDoorBlock(CLOUD.getDefaultState(), UWoodTypes.CLOUD, Settings.copy(CLOUD)), ItemGroups.FUNCTIONAL);
Block SPECTRAL_FIRE = register("spectral_fire", new SpectralFireBlock(Settings.copy(Blocks.SOUL_FIRE)));
Block JAR = register("jar", new ItemJarBlock(Settings.copy(Blocks.GLASS)));
Block CLOUD_JAR = register("cloud_jar", new JarBlock(Settings.copy(Blocks.GLASS)));
Block STORM_JAR = register("storm_jar", new JarBlock(Settings.copy(Blocks.GLASS)));
Block LIGHTNING_JAR = register("lightning_jar", new JarBlock(Settings.copy(Blocks.GLASS)));
Block ZAP_JAR = register("zap_jar", new JarBlock(Settings.copy(Blocks.GLASS)));
Block WORM_BLOCK = register("worm_block", new ColoredFallingBlock(new ColorCode(0xFF0088), Settings.create().hardness(0.1F).resistance(0).requiresTool().sounds(BlockSoundGroup.MUD)), ItemGroups.NATURAL);
EdibleBlock HAY_BLOCK = register("hay_block", new EdibleBlock(new Identifier("hay_block"), new Identifier("wheat"), true));
private static <T extends Block> T register(String name, T item) {
@ -301,7 +309,10 @@ public interface UBlocks {
OxidizableBlocksRegistry.registerWaxableBlockPair(ZAP_SLAB, WAXED_ZAP_SLAB);
OxidizableBlocksRegistry.registerWaxableBlockPair(ZAP_FENCE, WAXED_ZAP_FENCE);
OxidizableBlocksRegistry.registerWaxableBlockPair(ZAP_FENCE_GATE, WAXED_ZAP_FENCE_GATE);
Collections.addAll(TRANSLUCENT_BLOCKS, WEATHER_VANE, CHITIN_SPIKES, PLUNDER_VINE, PLUNDER_VINE_BUD, CLAM_SHELL, SCALLOP_SHELL, TURRET_SHELL, CURING_JOKE, SPECTRAL_FIRE);
Collections.addAll(TRANSLUCENT_BLOCKS,
WEATHER_VANE, CHITIN_SPIKES, PLUNDER_VINE, PLUNDER_VINE_BUD, CLAM_SHELL, SCALLOP_SHELL, TURRET_SHELL, CURING_JOKE, SPECTRAL_FIRE,
JAR, CLOUD_JAR, STORM_JAR, LIGHTNING_JAR, ZAP_JAR
);
TintedBlock.REGISTRY.add(PALM_LEAVES);
FlammableBlockRegistry.getDefaultInstance().add(GREEN_APPLE_LEAVES, 30, 60);
@ -326,6 +337,8 @@ public interface UBlocks {
FlammableBlockRegistry.getDefaultInstance().add(BANANAS, 5, 20);
FlammableBlockRegistry.getDefaultInstance().add(CURING_JOKE, 60, 100);
CompostingChanceRegistry.INSTANCE.add(WORM_BLOCK, 1F);
UBlockEntities.bootstrap();
EdibleBlock.bootstrap();
}

View file

@ -185,7 +185,7 @@ public class CloudBlock extends Block implements CloudLike {
}
protected boolean canInteract(BlockState state, BlockView world, BlockPos pos, EquineContext context) {
return context.collidesWithClouds();
return context.collidesWithClouds() || context.hasFeatherTouch();
}
@SuppressWarnings("deprecation")

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.block.cloud;
import java.util.Map;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
@ -9,13 +10,18 @@ import com.mojang.serialization.MapCodec;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.PillarBlock;
import net.minecraft.block.ShapeContext;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.BlockRotation;
import net.minecraft.util.Util;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Direction.AxisDirection;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
@ -23,29 +29,34 @@ import net.minecraft.world.WorldAccess;
public class CloudPillarBlock extends CloudBlock {
private static final MapCodec<CloudPillarBlock> CODEC = Block.createCodec(CloudPillarBlock::new);
private static final BooleanProperty NORTH = Properties.NORTH;
private static final BooleanProperty SOUTH = Properties.SOUTH;
public static final EnumProperty<Direction.Axis> AXIS = Properties.AXIS;
private static final BooleanProperty TOP = Properties.NORTH;
private static final BooleanProperty BOTTOM = Properties.SOUTH;
private static final Map<Direction, BooleanProperty> DIRECTION_PROPERTIES = Map.of(
Direction.UP, NORTH,
Direction.DOWN, SOUTH
Direction.UP, TOP, Direction.DOWN, BOTTOM,
Direction.SOUTH, TOP, Direction.NORTH, BOTTOM,
Direction.EAST, TOP, Direction.WEST, BOTTOM
);
private static final VoxelShape CORE_SHAPE = Block.createCuboidShape(1, 0, 1, 15, 16, 15);
private static final VoxelShape FOOT_SHAPE = Block.createCuboidShape(0, 0, 0, 16, 5, 16);
private static final VoxelShape CAP_SHAPE = FOOT_SHAPE.offset(0, 11F / 16F, 0);
private static final VoxelShape[] SHAPES = new VoxelShape[] {
CORE_SHAPE,
VoxelShapes.union(CORE_SHAPE, FOOT_SHAPE),
VoxelShapes.union(CORE_SHAPE, CAP_SHAPE),
VoxelShapes.union(CORE_SHAPE, FOOT_SHAPE, CAP_SHAPE)
private static final Function<Direction.Axis, VoxelShape[]> SHAPES = Util.memoize(axis -> {
int[] offsets = { axis.choose(1, 0, 0), axis.choose(0, 1, 0), axis.choose(0, 0, 1) };
float capOffset = 11F / 16F;
VoxelShape core = Block.createCuboidShape(
axis.choose(0, 1, 1), axis.choose(1, 0, 1), axis.choose(1, 1, 0),
16 - axis.choose(0, 1, 1), 16 - axis.choose(1, 0, 1), 16 - axis.choose(1, 1, 0)
);
VoxelShape foot = Block.createCuboidShape(0, 0, 0, 16 - (11 * offsets[0]), 16 - (11 * offsets[1]), 16 - (11 * offsets[2]));
VoxelShape cap = foot.offset(capOffset * offsets[0], capOffset * offsets[1], capOffset * offsets[2]);
return new VoxelShape[] {
core,
VoxelShapes.union(core, foot),
VoxelShapes.union(core, cap),
VoxelShapes.union(core, cap, foot)
};
// [0,0] [0,1]
// [1,0] [1,1]
});
public CloudPillarBlock(Settings settings) {
super(false, settings);
setDefaultState(getDefaultState().with(NORTH, true).with(SOUTH, true));
setDefaultState(getDefaultState().with(TOP, true).with(BOTTOM, true).with(AXIS, Direction.Axis.Y));
}
@Override
@ -55,32 +66,41 @@ public class CloudPillarBlock extends CloudBlock {
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(NORTH, SOUTH);
builder.add(AXIS, TOP, BOTTOM);
}
@Override
protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context, EquineContext equineContext) {
return SHAPES[(state.get(NORTH) ? 0 : 2) + (state.get(SOUTH) ? 0 : 1)];
return SHAPES.apply(state.get(AXIS))[(state.get(TOP) ? 0 : 2) + (state.get(BOTTOM) ? 0 : 1)];
}
@Override
@Nullable
protected BlockState getPlacementState(ItemPlacementContext placementContext, EquineContext equineContext) {
BlockPos pos = placementContext.getBlockPos();
BlockState state = super.getPlacementState(placementContext, equineContext);
for (var property : DIRECTION_PROPERTIES.entrySet()) {
state = state.with(property.getValue(), placementContext.getWorld().getBlockState(pos.offset(property.getKey())).isOf(this));
}
return state;
Direction.Axis axis = placementContext.getSide().getAxis();
Direction upDirection = Direction.get(AxisDirection.POSITIVE, axis);
Direction downDirection = Direction.get(AxisDirection.NEGATIVE, axis);
BlockState above = placementContext.getWorld().getBlockState(pos.offset(upDirection));
BlockState below = placementContext.getWorld().getBlockState(pos.offset(downDirection));
return super.getPlacementState(placementContext, equineContext)
.with(DIRECTION_PROPERTIES.get(upDirection), above.isOf(this) && above.get(AXIS) == axis)
.with(DIRECTION_PROPERTIES.get(downDirection), below.isOf(this) && below.get(AXIS) == axis)
.with(AXIS, axis);
}
@Deprecated
@Override
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
if (direction.getAxis() == Direction.Axis.Y) {
return state.with(DIRECTION_PROPERTIES.get(direction), neighborState.isOf(this));
if (direction.getAxis() == state.get(AXIS)) {
return state.with(DIRECTION_PROPERTIES.get(direction), neighborState.isOf(this) && neighborState.get(AXIS) == state.get(AXIS));
}
return state;
}
@Override
public BlockState rotate(BlockState state, BlockRotation rotation) {
return PillarBlock.changeRotation(state, rotation);
}
}

View file

@ -0,0 +1,80 @@
package com.minelittlepony.unicopia.block.jar;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import com.google.common.base.Suppliers;
import com.minelittlepony.unicopia.block.ItemJarBlock.FluidJarContents;
import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.minecraft.block.Blocks;
import net.minecraft.entity.Bucketable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registries;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.TypedActionResult;
public record EntityJarContents (
TileData tile,
@Nullable EntityType<?> entityType,
Supplier<@Nullable Entity> entity
) implements FluidJarContents {
public EntityJarContents(TileData tile, NbtCompound compound) {
this(tile, Registries.ENTITY_TYPE.getOrEmpty(Identifier.tryParse(compound.getString("entity"))).orElse(null));
}
public EntityJarContents(TileData tile) {
this(tile, (EntityType<?>)null);
}
public EntityJarContents(TileData tile, EntityType<?> entityType) {
this(tile, entityType, Suppliers.memoize(() -> {
return entityType == null ? null : entityType.create(tile.getWorld());
}));
}
@Override
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand);
if (stack.isOf(Items.BUCKET)) {
if (entity().get() instanceof Bucketable bucketable) {
consumeAndSwap(player, hand, bucketable.getBucketItem());
player.playSound(bucketable.getBucketFillSound(), 1, 1);
}
tile.markDirty();
return TypedActionResult.success(new ItemsJarContents(tile));
}
return TypedActionResult.pass(this);
}
@Override
public void onDestroyed() {
tile.getWorld().setBlockState(tile.getPos(), Blocks.WATER.getDefaultState());
Entity entity = entity().get();
if (entity != null) {
entity.refreshPositionAfterTeleport(tile.getPos().toCenterPos());
tile.getWorld().spawnEntity(entity);
}
}
@Override
public NbtCompound toNBT(NbtCompound compound) {
compound.putString("entity", EntityType.getId(entityType).toString());
return compound;
}
@Override
public FluidVariant fluid() {
return FluidVariant.of(Fluids.WATER);
}
}

View file

@ -0,0 +1,79 @@
package com.minelittlepony.unicopia.block.jar;
import java.util.Optional;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
import com.minelittlepony.unicopia.util.FluidHelper;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registries;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.TypedActionResult;
public record FakeFluidJarContents (
TileData tile,
String fluid,
int color,
Item empty,
Item filled
) implements JarContents {
public FakeFluidJarContents(TileData tile, NbtCompound compound) {
this(tile, compound.getString("fluid"), compound.getInt("color"),
Registries.ITEM.get(new Identifier(compound.getString("empty"))),
Registries.ITEM.get(new Identifier(compound.getString("filled"))));
}
@Override
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand);
tile.markDirty();
return getRealFluid().map(FluidVariant::of).<TypedActionResult<JarContents>>map(fluid -> {
long remainder = FluidHelper.deposit(stack, player, hand, fluid, FluidConstants.BUCKET);
fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
if (remainder > 0) {
return TypedActionResult.success(new FluidOnlyJarContents(tile, remainder, fluid));
}
return TypedActionResult.success(new ItemsJarContents(tile));
}).orElseGet(() -> {
if (!stack.isOf(empty)) {
return TypedActionResult.pass(this);
}
consumeAndSwap(player, hand, filled.getDefaultStack());
player.playSound("powder_snow".equalsIgnoreCase(fluid) ? USounds.Vanilla.ITEM_BUCKET_FILL_POWDER_SNOW : USounds.Vanilla.ITEM_BUCKET_FILL, 1, 1);
return TypedActionResult.success(new ItemsJarContents(tile));
});
}
@Override
public void onDestroyed() {
getRealFluid().ifPresent(fluid -> {
tile.getWorld().setBlockState(tile.getPos(), FluidHelper.getFullFluidState(FluidVariant.of(fluid)).getBlockState());
});
}
@Override
public NbtCompound toNBT(NbtCompound compound) {
compound.putString("fluid", fluid);
compound.putInt("color", color);
compound.putString("empty", Registries.ITEM.getId(empty).toString());
compound.putString("filled", Registries.ITEM.getId(filled).toString());
return compound;
}
private Optional<Fluid> getRealFluid() {
return Registries.FLUID.getIds().stream()
.filter(id -> id.getPath().equalsIgnoreCase(fluid))
.findFirst()
.map(Registries.FLUID::get);
}
}

View file

@ -0,0 +1,55 @@
package com.minelittlepony.unicopia.block.jar;
import com.minelittlepony.unicopia.block.ItemJarBlock.FluidJarContents;
import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
import com.minelittlepony.unicopia.util.FluidHelper;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
public record FluidOnlyJarContents (
TileData tile,
long amount,
FluidVariant fluid
) implements FluidJarContents {
public FluidOnlyJarContents(TileData tile, NbtCompound compound) {
this(tile, compound.getLong("amount"), FluidVariant.fromNbt(compound.getCompound("fluid")));
}
@Override
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
ItemStack stack = player.getStackInHand(hand);
if (stack.isOf(Items.BUCKET)) {
long remainder = FluidHelper.deposit(stack, player, hand, fluid, amount);
tile.markDirty();
fluid.getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
if (remainder > 0) {
return TypedActionResult.success(new FluidOnlyJarContents(tile, remainder, fluid));
}
return TypedActionResult.success(new ItemsJarContents(tile));
}
return TypedActionResult.pass(this);
}
@Override
public void onDestroyed() {
if (amount >= FluidConstants.BUCKET) {
tile.getWorld().setBlockState(tile.getPos(), FluidHelper.getFullFluidState(fluid).getBlockState());
}
}
@Override
public NbtCompound toNBT(NbtCompound compound) {
compound.put("fluid", fluid.toNbt());
compound.putLong("amount", amount);
return compound;
}
}

View file

@ -0,0 +1,208 @@
package com.minelittlepony.unicopia.block.jar;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.block.ItemJarBlock.JarContents;
import com.minelittlepony.unicopia.block.ItemJarBlock.TileData;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.mixin.MixinEntityBucketItem;
import com.minelittlepony.unicopia.util.FluidHelper;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.minecraft.block.Block;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.util.Hand;
import net.minecraft.util.Pair;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.math.Direction;
public record ItemsJarContents (
TileData tile,
List<ItemStack> stacks
) implements JarContents, SidedInventory {
private static final int[] SLOTS = IntStream.range(0, 16).toArray();
public ItemsJarContents(TileData tile) {
this(tile, new ArrayList<>());
}
public ItemsJarContents(TileData tile, NbtCompound compound) {
this(tile, NbtSerialisable.ITEM_STACK.readAll(compound.getList("items", NbtElement.COMPOUND_TYPE))
.limit(15)
.collect(Collectors.toList()));
}
@Override
public TypedActionResult<JarContents> interact(PlayerEntity player, Hand hand) {
ItemStack handStack = player.getStackInHand(hand);
if (handStack.isEmpty()) {
if (stacks.isEmpty()) {
return TypedActionResult.fail(this);
}
Block.dropStack(tile.getWorld(), tile.getPos(), stacks.remove(0));
markDirty();
return TypedActionResult.success(this);
}
if (stacks.isEmpty()) {
if (handStack.getItem() instanceof MixinEntityBucketItem bucket) {
consumeAndSwap(player, hand, Items.BUCKET.getDefaultStack());
player.playSound(bucket.getEmptyingSound(), 1, 1);
markDirty();
return TypedActionResult.success(new EntityJarContents(tile, bucket.getEntityType()));
}
Pair<Long, FluidVariant> fluid = FluidHelper.extract(handStack, player, hand).orElse(null);
if (fluid != null) {
fluid.getRight().getFluid().getBucketFillSound().ifPresent(sound -> player.playSound(sound, 1, 1));
markDirty();
return TypedActionResult.success(new FluidOnlyJarContents(tile, fluid.getLeft(), fluid.getRight()));
}
if (handStack.isOf(Items.MILK_BUCKET)) {
consumeAndSwap(player, hand, handStack.getRecipeRemainder());
player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
markDirty();
return TypedActionResult.success(new FakeFluidJarContents(tile, "milk", 0xFFFFFFFF, Items.BUCKET, Items.MILK_BUCKET));
}
if (handStack.isOf(Items.POWDER_SNOW_BUCKET)) {
consumeAndSwap(player, hand, Items.BUCKET.getDefaultStack());
player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY_POWDER_SNOW, 1, 1);
markDirty();
return TypedActionResult.success(new FakeFluidJarContents(tile, "powder_snow", 0xFFFFFFFF, Items.BUCKET, Items.POWDER_SNOW_BUCKET));
}
if (handStack.isOf(UItems.LOVE_BUCKET)) {
consumeAndSwap(player, hand, handStack.getRecipeRemainder());
player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
markDirty();
return TypedActionResult.success(new FakeFluidJarContents(tile, "love", 0xFF3030, Items.BUCKET, UItems.LOVE_BUCKET));
}
if (handStack.isOf(UItems.JUICE)) {
consumeAndSwap(player, hand, handStack.getRecipeRemainder());
player.playSound(USounds.Vanilla.ITEM_BUCKET_EMPTY, 1, 1);
markDirty();
return TypedActionResult.success(new FakeFluidJarContents(tile, "apple_juice", 0x30FF30, Items.GLASS_BOTTLE, UItems.JUICE));
}
}
if (stacks.size() >= size()) {
return TypedActionResult.fail(this);
}
stacks.add(player.isCreative() ? handStack.copyWithCount(1) : handStack.split(1));
markDirty();
return TypedActionResult.success(this);
}
@Override
public void onDestroyed() {
stacks.forEach(stack -> Block.dropStack(tile.getWorld(), tile.getPos(), stack));
}
@Override
public int size() {
return 15;
}
@Override
public boolean isEmpty() {
return stacks.isEmpty();
}
@Override
public ItemStack getStack(int slot) {
return slot < 0 || slot >= stacks.size() ? ItemStack.EMPTY : stacks.get(slot);
}
@Override
public ItemStack removeStack(int slot, int amount) {
if (slot < 0 || slot >= stacks.size()) {
return ItemStack.EMPTY;
}
try {
ItemStack stack = stacks.get(slot);
ItemStack removed = stack.split(1);
if (stack.isEmpty()) {
stacks.remove(slot);
}
return removed;
} finally {
markDirty();
}
}
@Override
public ItemStack removeStack(int slot) {
if (slot < 0 || slot >= stacks.size()) {
return ItemStack.EMPTY;
}
try {
return stacks.remove(slot);
} finally {
markDirty();
}
}
@Override
public void setStack(int slot, ItemStack stack) {
if (slot >= stacks.size()) {
stacks.add(stack);
} else {
stacks.set(slot, stack);
}
markDirty();
}
@Override
public boolean canPlayerUse(PlayerEntity player) {
return false;
}
@Override
public void clear() {
stacks.clear();
markDirty();
}
@Override
public int[] getAvailableSlots(Direction side) {
return SLOTS;
}
@Override
public boolean canInsert(int slot, ItemStack stack, Direction dir) {
return slot >= 0 && slot < size() && slot >= stacks.size();
}
@Override
public boolean canExtract(int slot, ItemStack stack, Direction dir) {
return slot >= 0 && slot < size() && slot < stacks.size();
}
@Override
public NbtCompound toNBT(NbtCompound compound) {
compound.put("items", NbtSerialisable.ITEM_STACK.writeAll(stacks));
return compound;
}
@Override
public void markDirty() {
tile.markDirty();
}
}

View file

@ -41,6 +41,8 @@ import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.World;
@ -161,4 +163,9 @@ public class ClientInteractionManager extends InteractionManager {
c.networkHandler.sendPacket(new PlayerMoveC2SPacket.LookAndOnGround(player.getYaw(), player.getPitch(), player.isOnGround()));
}
}
@Override
public void addBlockBreakingParticles(BlockPos pos, Direction direction) {
client.particleManager.addBlockBreakingParticles(pos, direction);
}
}

View file

@ -12,6 +12,7 @@ import com.minelittlepony.unicopia.client.particle.CloudsEscapingParticle;
import com.minelittlepony.unicopia.client.particle.DiskParticle;
import com.minelittlepony.unicopia.client.particle.DustCloudParticle;
import com.minelittlepony.unicopia.client.particle.FloatingBubbleParticle;
import com.minelittlepony.unicopia.client.particle.FootprintParticle;
import com.minelittlepony.unicopia.client.particle.GroundPoundParticle;
import com.minelittlepony.unicopia.client.particle.HealthDrainParticle;
import com.minelittlepony.unicopia.client.particle.LightningBoltParticle;
@ -19,7 +20,6 @@ import com.minelittlepony.unicopia.client.particle.MagicParticle;
import com.minelittlepony.unicopia.client.particle.RainboomParticle;
import com.minelittlepony.unicopia.client.particle.RainbowTrailParticle;
import com.minelittlepony.unicopia.client.particle.RaindropsParticle;
import com.minelittlepony.unicopia.client.particle.RunesParticle;
import com.minelittlepony.unicopia.client.particle.ShockwaveParticle;
import com.minelittlepony.unicopia.client.particle.SphereParticle;
import com.minelittlepony.unicopia.client.render.*;
@ -54,6 +54,7 @@ import net.minecraft.client.particle.SpriteProvider;
import net.minecraft.client.render.*;
import net.minecraft.client.render.VertexConsumerProvider.Immediate;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactories;
import net.minecraft.client.render.entity.EmptyEntityRenderer;
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
@ -68,7 +69,6 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
@SuppressWarnings("deprecation")
public interface URenderers {
BlockEntity CHEST_RENDER_ENTITY = new CloudChestBlock.TileData(BlockPos.ORIGIN, UBlocks.CLOUD_CHEST.getDefaultState());
@ -78,10 +78,10 @@ public interface URenderers {
ParticleFactoryRegistry.getInstance().register(UParticles.BUBBLE, createFactory(FloatingBubbleParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.RAIN_DROPS, createFactory(RaindropsParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create));
ParticleFactoryRegistry.getInstance().register(UParticles.FOOTPRINT, createFactory(FootprintParticle::new));
ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_RING, RainboomParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_TRAIL, RainbowTrailParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.SHOCKWAVE, ShockwaveParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.MAGIC_RUNES, RunesParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.SPHERE, SphereParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.DISK, DiskParticle::new);
ParticleFactoryRegistry.getInstance().register(UParticles.GROUND_POUND, GroundPoundParticle::new);
@ -111,10 +111,12 @@ public interface URenderers {
EntityRendererRegistry.register(UEntities.LOOT_BUG, LootBugEntityRenderer::new);
EntityRendererRegistry.register(UEntities.TENTACLE, TentacleEntityRenderer::new);
EntityRendererRegistry.register(UEntities.IGNOMINIOUS_BULB, IgnominiousBulbEntityRenderer::new);
EntityRendererRegistry.register(UEntities.SPECTER, EmptyEntityRenderer::new);
BlockEntityRendererFactories.register(UBlockEntities.WEATHER_VANE, WeatherVaneBlockEntityRenderer::new);
BlockEntityRendererFactories.register(UBlockEntities.FANCY_BED, CloudBedBlockEntityRenderer::new);
BlockEntityRendererFactories.register(UBlockEntities.CLOUD_CHEST, CloudChestBlockEntityRenderer::new);
BlockEntityRendererFactories.register(UBlockEntities.ITEM_JAR, ItemJarBlockEntityRenderer::new);
register(URenderers::renderJarItem, UItems.FILLED_JAR);
register(URenderers::renderBedItem, UItems.CLOTH_BED, UItems.CLOUD_BED);

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.client;
import java.util.Optional;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import com.minelittlepony.common.client.gui.element.Button;
import com.minelittlepony.common.event.ScreenInitCallback;
@ -33,11 +34,14 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.OpenToLanScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.client.render.Camera;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.resource.ResourceType;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class UnicopiaClient implements ClientModInitializer {
@ -66,6 +70,20 @@ public class UnicopiaClient implements ClientModInitializer {
return Optional.empty();
}
public static Vec3d getAdjustedSoundPosition(Vec3d pos) {
PlayerCamera cam = getCamera().orElse(null);
if (cam == null) {
return pos;
}
Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera();
Vector3f rotated = pos.subtract(camera.getPos()).toVector3f();
rotated = rotated.rotateAxis(cam.calculateRoll() * MathHelper.RADIANS_PER_DEGREE, 0, 1, 0);
return new Vec3d(rotated).add(camera.getPos());
}
public static Race getPreferredRace() {
if (!Unicopia.getConfig().ignoreMineLP.get()
&& MinecraftClient.getInstance().player != null) {

View file

@ -7,7 +7,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
import com.minelittlepony.unicopia.client.gui.DrawableUtil;
import com.minelittlepony.unicopia.client.gui.MagicText;
import com.minelittlepony.unicopia.container.SpellbookState;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.recipe.URecipes;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.DrawContext;

View file

@ -0,0 +1,74 @@
package com.minelittlepony.unicopia.client.particle;
import org.joml.Vector3f;
import com.minelittlepony.unicopia.particle.FootprintParticleEffect;
import net.minecraft.client.particle.ParticleTextureSheet;
import net.minecraft.client.particle.SpriteBillboardParticle;
import net.minecraft.client.particle.SpriteProvider;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class FootprintParticle extends SpriteBillboardParticle {
// specter
public FootprintParticle(FootprintParticleEffect effect, SpriteProvider provider, ClientWorld world, double x, double y, double z, double dx, double dy, double dz) {
super(world, x, y, z, 0, 0, 0);
setVelocity(0, 0, 0);
setSprite(provider.getSprite(world.random));
this.angle = effect.yaw() * MathHelper.RADIANS_PER_DEGREE;
this.maxAge = 1000;
this.gravityStrength = 1;
}
@Override
public ParticleTextureSheet getType() {
return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT;
}
@Override
public void tick() {
super.tick();
}
@Override
public void buildGeometry(VertexConsumer drawer, Camera camera, float tickDelta) {
Vec3d cam = camera.getPos();
float renderX = (float)(MathHelper.lerp(tickDelta, prevPosX, x) - cam.getX());
float renderY = (float)(MathHelper.lerp(tickDelta, prevPosY, y) - cam.getY());
float renderZ = (float)(MathHelper.lerp(tickDelta, prevPosZ, z) - cam.getZ());
Vector3f[] corners = new Vector3f[]{
new Vector3f(-1, 0, -1),
new Vector3f(-1, 0, 1),
new Vector3f( 1, 0, 1),
new Vector3f( 1, 0, -1)
};
for (int k = 0; k < 4; ++k) {
Vector3f corner = corners[k];
corner.mul(0.2F);
corner.rotateAxis(angle, 0, 1, 0);
corner.add(renderX, renderY + 0.0001F, renderZ);
}
float alpha = this.alpha * (1 - ((float)age / maxAge));
int light = getBrightness(tickDelta);
float minU = this.sprite.getMinU();
float maxU = this.sprite.getMaxU();
float minV = this.sprite.getMinV();
float maxV = this.sprite.getMaxV();
drawer.vertex(corners[0].x, corners[0].y, corners[0].z).texture(minU, minV).color(red, green, blue, alpha).light(light).next();
drawer.vertex(corners[1].x, corners[1].y, corners[1].z).texture(maxU, minV).color(red, green, blue, alpha).light(light).next();
drawer.vertex(corners[2].x, corners[2].y, corners[2].z).texture(maxU, maxV).color(red, green, blue, alpha).light(light).next();
drawer.vertex(corners[3].x, corners[3].y, corners[3].z).texture(minU, maxV).color(red, green, blue, alpha).light(light).next();
}
}

View file

@ -1,123 +0,0 @@
package com.minelittlepony.unicopia.client.particle;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.*;
@Deprecated
public class RunesParticle extends OrientedBillboardParticle {
private static final Identifier[] TEXTURES = new Identifier[] {
Unicopia.id("textures/particles/runes_0.png"),
Unicopia.id("textures/particles/runes_1.png"),
Unicopia.id("textures/particles/runes_2.png"),
Unicopia.id("textures/particles/runes_3.png"),
Unicopia.id("textures/particles/runes_4.png"),
Unicopia.id("textures/particles/runes_5.png")
};
protected float targetSize = 3;
protected float prevBaseSize = 0;
protected float baseSize = 0;
private float prevRotationAngle;
private float rotationAngle;
public RunesParticle(OrientedBillboardParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
super(effect, world, x, y, z, velocityX, velocityY, velocityZ);
setMaxAge(70);
red = world.random.nextFloat();
green = world.random.nextFloat();
blue = world.random.nextFloat();
}
@Override
public float getScale(float tickDelta) {
return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * super.getScale(tickDelta);
}
@Override
protected Identifier getTexture() {
return TEXTURES[0];
}
private float getAlphaScale() {
float transitionScale = age < maxAge / 2 ? 5 : 3;
return (float)Math.min(1, Math.sin(Math.PI * age / maxAge) * transitionScale);
}
@Override
protected int getBrightness(float tint) {
return 0xF000F0;
}
@Override
protected void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta) {
float alpha = this.alpha * getAlphaScale();
float angle = MathHelper.lerp(tickDelta, prevRotationAngle, rotationAngle);
for (int i = 0; i < TEXTURES.length; i++) {
for (int dim = 0; dim < 3; dim++) {
RenderSystem.setShaderTexture(0, TEXTURES[i]);
RenderSystem.setShaderColor(red, green, blue, alpha / ((float)(dim * 3) + 1));
Vector3f[] corners = new Vector3f[]{
new Vector3f(-1, -1, 0),
new Vector3f(-1, 1, 0),
new Vector3f( 1, 1, 0),
new Vector3f( 1, -1, 0)
};
float scale = getScale(tickDelta);
float ringSpeed = (i % 2 == 0 ? i : -1) * i;
Quaternionf ringAngle = RotationAxis.POSITIVE_Z.rotationDegrees(angle * ringSpeed);
Quaternionf ringFlip = RotationAxis.POSITIVE_Y.rotationDegrees(angle * ringSpeed * dim);
Quaternionf ringRoll = RotationAxis.POSITIVE_X.rotationDegrees(angle * ringSpeed * dim);
for(int k = 0; k < 4; ++k) {
Vector3f corner = corners[k];
corner.rotate(ringAngle);
corner.rotate(ringFlip);
corner.rotate(ringRoll);
corner.rotate(rotation);
corner.mul(scale);
corner.add(x, y + 0.001F, z);
}
renderQuad(te, buffer, corners, alpha, tickDelta);
}
}
RenderSystem.setShaderColor(1, 1, 1, 1);
}
@Override
public void tick() {
super.tick();
prevBaseSize = baseSize;
if (baseSize < targetSize) {
baseSize += 0.1F;
}
if (baseSize > targetSize) {
baseSize -= 0.1F;
}
rotationAngle = (rotationAngle + 0.3F) % 360;
prevRotationAngle = rotationAngle - 0.3F;
}
}

View file

@ -53,7 +53,7 @@ public class PlayerPoser {
float pitchChange = -0.5F;
float yawChange = 0.8F;
if (player.getStackInHand(rightHand).isIn(UTags.POLEARMS) && (!ponyRace.isEquine() || model.rightArm.pitch != 0)) {
if (player.getStackInHand(rightHand).isIn(UTags.Items.POLEARMS) && (!ponyRace.isEquine() || model.rightArm.pitch != 0)) {
model.rightArm.pitch += pitchChange;
model.rightArm.yaw += yawChange;
if (player.handSwingTicks > 0 && rightHand == Hand.MAIN_HAND) {
@ -62,7 +62,7 @@ public class PlayerPoser {
}
}
if (player.getStackInHand(leftHand).isIn(UTags.POLEARMS) && (!ponyRace.isEquine() || model.leftArm.pitch != 0)) {
if (player.getStackInHand(leftHand).isIn(UTags.Items.POLEARMS) && (!ponyRace.isEquine() || model.leftArm.pitch != 0)) {
model.leftArm.pitch += pitchChange;
model.leftArm.yaw -= yawChange;
if (player.handSwingTicks > 0 && leftHand == Hand.MAIN_HAND) {

View file

@ -12,7 +12,8 @@ import net.minecraft.client.util.math.MatrixStack;
public class RenderUtil {
public static final Vector4f TEMP_VECTOR = new Vector4f();
private static final Vector4f TEMP_UV_VECTOR = new Vector4f();
public static final Vector4f TEMP_UV_VECTOR = new Vector4f();
public static final Vector3f TEMP_NORMAL_VECTOR = new Vector3f();
public static final Vertex[] UNIT_FACE = new Vertex[] {
new Vertex(0, 0, 0, 1, 1),
new Vertex(0, 1, 0, 1, 0),
@ -26,6 +27,9 @@ public class RenderUtil {
new Vertex(0, 0, 0, 0, 1)
};
public static void renderFace(MatrixStack matrices, Tessellator te, BufferBuilder buffer, float r, float g, float b, float a, int light) {
renderFace(matrices, te, buffer, r, g, b, a, light, 1, 1);
}

View file

@ -167,52 +167,46 @@ public class WorldRenderDelegate {
return true;
}
pony.updateSupportingEntity();
matrices.push();
Entity owner = pony.asEntity();
boolean negative = pony.getPhysics().isGravityNegative();
float roll = negative ? 180 : 0;
roll = pony instanceof Pony ? ((Pony)pony).getInterpolator().interpolate("g_roll", roll, 15) : roll;
matrices.translate(x, y + owner.getHeight() / 2, z);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(roll));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(roll));
if (pony instanceof Pony p) {
roll = p.getCamera().calculateRoll();
if (negative) {
roll -= 180;
}
float sidewaysRoll = p.getCamera().calculateRoll();
if (p.getAcrobatics().isFloppy()) {
matrices.translate(0, -0.5, 0);
p.asEntity().setBodyYaw(0);
p.asEntity().setYaw(0);
matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(90));
sidewaysRoll += 90;
}
matrices.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw));
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(90));
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(sidewaysRoll));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-90));
float diveAngle = p.getInterpolator().interpolate("g_kdive", p.getMotion().isDiving() ? 80 : 0, 15);
float forwardPitch = p.getInterpolator().interpolate("g_kdive", p.getMotion().isDiving() ? 80 : 0, 15);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(diveAngle));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw));
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(forwardPitch));
if (p.getCompositeRace().includes(Race.SEAPONY)
&& pony.asEntity().isSubmergedInWater()
&& MineLPDelegate.getInstance().getPlayerPonyRace(p.asEntity()) != Race.SEAPONY) {
ModelPartHooks.startCollecting();
}
} else if (pony instanceof Creature creature && smittenEyesRenderer.isSmitten(creature)) {
} else {
float roll = negative ? 180 : 0;
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll));
if (pony instanceof Creature creature && smittenEyesRenderer.isSmitten(creature)) {
ModelPartHooks.startCollecting();
}
}
matrices.translate(-x, -y - owner.getHeight() / 2, -z);
@ -224,7 +218,7 @@ public class WorldRenderDelegate {
}
private void flipAngles(Entity entity) {
if (entity instanceof PlayerEntity) {
if (entity instanceof PlayerEntity player) {
entity.prevYaw *= -1;
entity.setYaw(entity.getYaw() * -1);

View file

@ -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,30 +15,37 @@ import net.minecraft.util.math.MathHelper;
public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
private final ModelPart root;
private ModelPart main;
private float inflation;
private boolean isBurner;
private boolean isBalloon;
private boolean isSandbags;
private final List<ModelPart> ropes;
private final List<ModelPart> 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");
main = root.getChild(isBalloon ? "canopy" : "burner");
ropes = List.of(
part.getChild("rope_a"),
part.getChild("rope_b"),
part.getChild("rope_c"),
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 {
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() {
@ -60,12 +68,34 @@ public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
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);
}
@ -80,28 +110,123 @@ public class AirBalloonEntityModel extends EntityModel<AirBalloonEntity> {
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);
root.roll = MathHelper.sin((float)(entity.getX() - entity.prevX));
root.pitch = MathHelper.sin((float)(entity.getZ() - entity.prevZ));
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;
}
} else {
root.pitch = 0;
root.roll = 0;
}
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);
}
ropes.forEach(rope -> {
rope.visible = lifted;
});
if (isBalloon) {
root.pivotY = 0;
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 || 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);
}
}
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;
}
}
for (int i = 0; i < ropes.size(); i++) {
ModelPart rope = ropes.get(i);
float rollRatio = root.roll / rope.roll;
float pitchRatio = root.pitch / rope.pitch;
rope.pivotY -= 5F * rollRatio;
rope.pivotY -= 5F * pitchRatio;
if (i == 0 || i == 3) {
rope.pivotZ -= 5 * pitchRatio;
}
if (i == 2 || i == 1) {
rope.pivotZ += 5 * pitchRatio;
}
if (i == 2 || i == 3) {
rope.pivotX -= 5 * rollRatio;
}
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 {
ropes.forEach(ModelPart::resetTransform);
rope.xScale = 0.3F;
rope.zScale = 0.3F;
}
}
}
@Override

View file

@ -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<AirBalloonEntity, AirBalloonEntityModel> {
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<AirBalloonEntity
super.render(entity, yaw, tickDelta, matrices, vertices, light);
if (MinecraftClient.getInstance().getEntityRenderDispatcher().shouldRenderHitboxes() && !entity.isInvisible() && !MinecraftClient.getInstance().hasReducedDebugInfo()) {
for (Box box : entity.getBoundingBoxes()) {
WorldRenderer.drawBox(matrices, vertices.getBuffer(RenderLayer.getLines()), box.offset(entity.getPos().multiply(-1)), 1.0f, 1.0f, 1.0f, 1.0f);
}
MultiBox.forEach(entity.getBoundingBox(), box -> {
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 Predicate<AirBalloonEntity> visibilityTest;
private final Function<AirBalloonEntity, Identifier> textureFunc;
private final BiFunction<Integer, AirBalloonEntity, Integer> lightFunc;
public BalloonFeature(AirBalloonEntityModel model,
FeatureRendererContext<AirBalloonEntity, AirBalloonEntityModel> context,
Predicate<AirBalloonEntity> visibilityTest,
Function<AirBalloonEntity, Identifier> textureFunc) {
Function<AirBalloonEntity, Identifier> textureFunc,
BiFunction<Integer, AirBalloonEntity, Integer> 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);
}
}
}

View file

@ -100,7 +100,7 @@ public class CloudBedBlockEntityRenderer implements BlockEntityRenderer<CloudBed
false,
false
);
if (pattern != CloudBedBlock.SheetPattern.NONE) {
if (pattern != CloudBedBlock.SheetPattern.NONE && pattern != CloudBedBlock.SheetPattern.WHITE) {
renderModel(matrices, vertices,
state.get(BedBlock.PART) == BedPart.HEAD ? bedSheetsHead : bedSheetsFoot,
state.get(BedBlock.FACING),

View file

@ -0,0 +1,185 @@
package com.minelittlepony.unicopia.client.render.entity;
import java.util.Arrays;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.common.util.Color;
import com.minelittlepony.unicopia.block.ItemJarBlock;
import com.minelittlepony.unicopia.block.ItemJarBlock.FluidJarContents;
import com.minelittlepony.unicopia.block.jar.ItemsJarContents;
import com.minelittlepony.unicopia.block.jar.FakeFluidJarContents;
import com.minelittlepony.unicopia.block.jar.EntityJarContents;
import com.minelittlepony.unicopia.client.render.model.CubeModel;
import com.minelittlepony.unicopia.util.FluidHelper;
import com.minelittlepony.unicopia.util.PosHelper;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.command.argument.EntityAnchorArgumentType.EntityAnchor;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.World;
public class ItemJarBlockEntityRenderer implements BlockEntityRenderer<ItemJarBlock.TileData> {
private static final Direction[] GLASS_SIDES = Arrays.stream(PosHelper.ALL).filter(i -> i != Direction.UP).toArray(Direction[]::new);
private final ItemRenderer itemRenderer;
private final EntityRenderDispatcher dispatcher;
public ItemJarBlockEntityRenderer(BlockEntityRendererFactory.Context ctx) {
itemRenderer = ctx.getItemRenderer();
dispatcher = ctx.getEntityRenderDispatcher();
}
@Override
public void render(ItemJarBlock.TileData data, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
ItemsJarContents items = data.getItems();
if (items != null) {
renderItemStacks(data, items, tickDelta, matrices, vertices, light, overlay);
}
EntityJarContents entity = data.getEntity();
if (entity != null) {
renderEntity(data, entity, tickDelta, matrices, vertices, light, overlay);
}
FluidJarContents fluid = data.getFluid();
if (fluid != null) {
renderFluid(data, fluid, tickDelta, matrices, vertices, light, overlay);
}
FakeFluidJarContents milk = data.getFakeFluid();
if (milk != null) {
renderFluid(data, Fluids.WATER.getDefaultState(), milk.color(), FluidConstants.BUCKET, tickDelta, matrices, vertices, light, overlay);
}
}
private void renderItemStacks(ItemJarBlock.TileData data, ItemsJarContents items, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
float itemScale = 0.35F;
matrices.push();
matrices.translate(0.5, 0, 0.5);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
matrices.scale(itemScale, itemScale, itemScale);
Random rng = Random.create(data.getPos().asLong());
float y = 0;
for (ItemStack stack : items.stacks()) {
matrices.push();
matrices.translate((rng.nextFloat() - 0.5F) * 0.5F, (rng.nextFloat() - 0.5F) * 0.8F, -0.05 + y);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees((rng.nextFloat() * 360) - 180));
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees((rng.nextFloat() * 360) - 180));
y -= 0.1F;
itemRenderer.renderItem(stack, ModelTransformationMode.FIXED, light, overlay, matrices, vertices, data.getWorld(), 0);
matrices.pop();
}
matrices.pop();
}
private void renderEntity(ItemJarBlock.TileData data, EntityJarContents entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
Entity e = entity.entity().get();
if (e != null) {
PlayerEntity player = MinecraftClient.getInstance().player;
int age = player == null ? 0 : player.age;
float fullTick = age + tickDelta;
float size = Math.max(e.getWidth(), e.getHeight());
float desiredSize = 0.25F;
float scale = desiredSize / size;
float eyePos = (e.getEyeHeight(e.getPose())) * scale;
float yaw = 0;
if (player != null) {
Vec3d center = data.getPos().toCenterPos();
Vec3d observerPos = MinecraftClient.getInstance().gameRenderer.getCamera().getPos();
e.setPosition(center);
e.lookAt(EntityAnchor.FEET, observerPos);
}
matrices.push();
matrices.translate(0.5, 0.48 + MathHelper.sin(fullTick / 19F) * 0.02F - eyePos, 0.5);
matrices.scale(scale, scale, scale);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(10 * MathHelper.sin(fullTick / 19F)));
dispatcher.render(e, 0, 0, 0, yaw * MathHelper.RADIANS_PER_DEGREE, tickDelta, matrices, vertices, light);
matrices.pop();
}
}
private void renderFluid(ItemJarBlock.TileData data, FluidJarContents fluid, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
FluidState state = FluidHelper.getFullFluidState(fluid.fluid());
int color = getFluidColor(data.getWorld(), data.getPos(), state);
renderFluid(data, state, color, fluid.amount(), tickDelta, matrices, vertices, light, overlay);
}
private void renderFluid(ItemJarBlock.TileData data, FluidState state, int color, long amount, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertices, int light, int overlay) {
Sprite[] sprite = getFluidSprite(data.getWorld(), data.getPos(), state);
matrices.push();
Sprite topSprite = sprite[0];
float height = 0.6F * (amount / (float)FluidConstants.BUCKET);
boolean opaque = Color.a(color) >= 1;
CubeModel.render(
matrices,
vertices.getBuffer(opaque ? RenderLayer.getEntitySolid(topSprite.getAtlasId()) : RenderLayer.getEntityTranslucent(topSprite.getAtlasId())),
topSprite.getMinU(), topSprite.getMinV(),
topSprite.getMaxU(), topSprite.getMaxV(),
0.28F, 0.01F, 0.28F,
0.73F, 0.01F + height, 0.73F,
color,
light, overlay, Direction.UP
);
Sprite sideSprite = sprite[sprite.length - 1];
CubeModel.render(
matrices,
vertices.getBuffer(opaque ? RenderLayer.getEntitySolid(sideSprite.getAtlasId()) : RenderLayer.getEntityTranslucent(sideSprite.getAtlasId())),
sideSprite.getMinU(), sideSprite.getMinV(),
sideSprite.getMaxU(), sideSprite.getMaxV(),
0.28F, 0.01F, 0.28F,
0.73F, 0.01F + height, 0.73F,
color,
light, overlay, GLASS_SIDES
);
matrices.pop();
}
private int getFluidColor(World world, BlockPos pos, FluidState state) {
return getFluidHandler(state.getFluid()).getFluidColor(world, pos, state);
}
private Sprite[] getFluidSprite(@Nullable World world, BlockPos pos, FluidState state) {
return getFluidHandler(state.getFluid()).getFluidSprites(world, pos, state);
}
private FluidRenderHandler getFluidHandler(Fluid fluid) {
FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluid);
if (handler == null) {
return FluidRenderHandlerRegistry.INSTANCE.get(Fluids.WATER);
}
return handler;
}
}

View file

@ -0,0 +1,77 @@
package com.minelittlepony.unicopia.client.render.model;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import com.minelittlepony.common.util.Color;
import com.minelittlepony.unicopia.client.render.RenderUtil;
import com.minelittlepony.unicopia.client.render.RenderUtil.Vertex;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Direction;
public class CubeModel {
private static final Vector2f TEMP_UV_VECTOR = new Vector2f();
private static final Vertex[][] CUBE_VERTICES = {
new Vertex[] {
new Vertex(0, 0, 0, 0, 0),
new Vertex(1, 0, 0, 1, 0),
new Vertex(1, 0, 1, 1, 1),
new Vertex(0, 0, 1, 0, 1)
},
new Vertex[] {
new Vertex(0, 1, 0, 0, 0),
new Vertex(0, 1, 1, 0, 1),
new Vertex(1, 1, 1, 1, 1),
new Vertex(1, 1, 0, 1, 0)
},
new Vertex[] {
new Vertex(0, 0, 0, 0, 0),
new Vertex(0, 1, 0, 0, 1),
new Vertex(1, 1, 0, 1, 1),
new Vertex(1, 0, 0, 1, 0)
},
new Vertex[] {
new Vertex(0, 0, 1, 0, 0),
new Vertex(1, 0, 1, 1, 0),
new Vertex(1, 1, 1, 1, 1),
new Vertex(0, 1, 1, 0, 1)
},
new Vertex[] {
new Vertex(0, 0, 0, 0, 0),
new Vertex(0, 0, 1, 1, 0),
new Vertex(0, 1, 1, 1, 1),
new Vertex(0, 1, 0, 0, 1)
},
new Vertex[] {
new Vertex(1, 0, 0, 0, 0),
new Vertex(1, 1, 0, 1, 0),
new Vertex(1, 1, 1, 1, 1),
new Vertex(1, 0, 1, 0, 1)
}
};
public static void render(MatrixStack matrices, VertexConsumer buffer,
float u0, float v0, float u1, float v1,
float x0, float y0, float z0, float x1, float y1, float z1,
int color, int light, int overlay,
Direction... directions) {
float r = Color.r(color), g = Color.g(color), b = Color.b(color);
float du = u1 - u0, dv = v1 - v0;
float dx = x1 - x0, dy = y1 - y0, dz = z1 - z0;
Matrix4f position = matrices.peek().getPositionMatrix();
Matrix3f normal = matrices.peek().getNormalMatrix();
for (Direction direction : directions) {
for (Vertex vertex : CUBE_VERTICES[direction.ordinal()]) {
Vector4f pos = position.transform(RenderUtil.TEMP_VECTOR.set(vertex.position(), 1).mul(dx, dy, dz, 1).add(x0, y0, z0, 0));
Vector2f tex = TEMP_UV_VECTOR.set(vertex.texture().x, vertex.texture().y).mul(du, dv).add(u0, v0);
Vector3f norm = normal.transform(RenderUtil.TEMP_NORMAL_VECTOR.set(direction.getOffsetX(), direction.getOffsetY(), direction.getOffsetZ()));
buffer.vertex(pos.x, pos.y, pos.z, r, g, b, 1, tex.x, tex.y, overlay, light, norm.x, norm.y, norm.z);
}
}
}
}

View file

@ -1,15 +1,15 @@
package com.minelittlepony.unicopia.command;
import java.util.Arrays;
import java.util.stream.Stream;
import com.google.common.collect.Streams;
import com.minelittlepony.unicopia.entity.player.Pony;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import com.minelittlepony.unicopia.entity.Living;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
@ -22,45 +22,48 @@ class GravityCommand {
return CommandManager.literal("gravity").requires(s -> s.hasPermissionLevel(2))
.then(CommandManager.literal("get")
.executes(context -> get(context.getSource(), context.getSource().getPlayer(), true))
.then(CommandManager.argument("target", EntityArgumentType.player())
.executes(context -> get(context.getSource(), EntityArgumentType.getPlayer(context, "target"), false))
.then(CommandManager.argument("target", EntityArgumentType.entity())
.executes(context -> get(context.getSource(), EntityArgumentType.getEntity(context, "target"), false))
))
.then(CommandManager.literal("set")
.then(CommandManager.argument("gravity", FloatArgumentType.floatArg(-99, 99))
.executes(context -> set(context.getSource(), context.getSource().getPlayer(), FloatArgumentType.getFloat(context, "gravity"), true))
.then(CommandManager.argument("target", EntityArgumentType.player())
.executes(context -> set(context.getSource(), EntityArgumentType.getPlayer(context, "target"), FloatArgumentType.getFloat(context, "gravity"), false))
.executes(context -> set(context.getSource(), List.of(context.getSource().getPlayer()), FloatArgumentType.getFloat(context, "gravity"), true))
.then(CommandManager.argument("target", EntityArgumentType.entities())
.executes(context -> set(context.getSource(), EntityArgumentType.getEntities(context, "target"), FloatArgumentType.getFloat(context, "gravity"), false))
)));
}
static int get(ServerCommandSource source, PlayerEntity player, boolean isSelf) throws CommandSyntaxException {
sendFeedback(source, player, "get", false, Pony.of(player).getPhysics().getGravityModifier());
return 0;
}
static int get(ServerCommandSource source, Entity target, boolean isSelf) throws CommandSyntaxException {
Living<?> l = Living.living(target);
static int set(ServerCommandSource source, PlayerEntity player, float gravity, boolean isSelf) {
Pony iplayer = Pony.of(player);
iplayer.getPhysics().setBaseGravityModifier(gravity);
iplayer.setDirty();
sendFeedback(source, player, "set", true, gravity);
return 0;
}
static void sendFeedback(ServerCommandSource source, PlayerEntity player, String key, boolean notifyTarget, Object...arguments) {
String translationKey = "commands.gravity." + key;
if (source.getEntity() == player) {
source.sendFeedback(() -> Text.translatable(translationKey + ".self", arguments), true);
float gravity = l == null ? 1 : l.getPhysics().getGravityModifier();
if (source.getEntity() == target) {
source.sendFeedback(() -> Text.translatable("commands.gravity.get.self", gravity), true);
} else {
if (notifyTarget && source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) {
player.sendMessage(Text.translatable(translationKey, arguments));
source.sendFeedback(() -> Text.translatable("commands.gravity.get.other", target.getDisplayName(), gravity), true);
}
return 0;
}
source.sendFeedback(() -> Text.translatable(translationKey + ".other", Streams.concat(Stream.of(player.getDisplayName()), Arrays.stream(arguments)).toArray()), true);
static int set(ServerCommandSource source, Collection<? extends Entity> targets, float gravity, boolean isSelf) {
List<Entity> affected = targets.stream().map(Living::living).filter(Objects::nonNull).map(l -> {
l.getPhysics().setBaseGravityModifier(gravity);
l.setDirty();
if (l.asEntity() instanceof PlayerEntity player) {
if (source.getEntity() == player) {
player.sendMessage(Text.translatable("commands.gravity.set.self", gravity));
} else if (source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) {
player.sendMessage(Text.translatable("commands.gravity.set.other", l.asEntity().getDisplayName(), gravity));
}
}
return (Entity)l.asEntity();
}).toList();
if (affected.size() == 1) {
source.sendFeedback(() -> Text.translatable("commands.gravity.set.other", affected.get(0).getDisplayName()), true);
} else {
source.sendFeedback(() -> Text.translatable("commands.gravity.set.multiple", affected.size()), true);
}
return 0;
}
}

View file

@ -15,10 +15,10 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.block.state.Schematic;
import com.minelittlepony.unicopia.item.EnchantableItem;
import com.minelittlepony.unicopia.item.TransformCropsRecipe;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.item.group.MultiItem;
import com.minelittlepony.unicopia.recipe.TransformCropsRecipe;
import com.minelittlepony.unicopia.recipe.URecipes;
import dev.emi.emi.api.EmiPlugin;
import dev.emi.emi.api.EmiRegistry;

View file

@ -1,7 +1,7 @@
package com.minelittlepony.unicopia.container;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.recipe.URecipes;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;

View file

@ -10,7 +10,7 @@ import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
import com.minelittlepony.unicopia.container.inventory.*;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.recipe.URecipes;
import com.mojang.datafixers.util.Pair;
import net.minecraft.enchantment.EnchantmentHelper;

View file

@ -22,6 +22,10 @@ public class DataCollector {
this.resolver = resolver;
}
public boolean isDefined(Identifier id) {
return values.containsKey(id);
}
public BiConsumer<Identifier, Supplier<JsonElement>> prime() {
values.clear();
return (Identifier id, Supplier<JsonElement> value) ->

View file

@ -3,49 +3,75 @@ package com.minelittlepony.unicopia.datagen;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.minelittlepony.unicopia.block.EdibleBlock;
import com.minelittlepony.unicopia.datagen.providers.DietsProvider;
import com.minelittlepony.unicopia.datagen.providers.SeasonsGrowthRatesProvider;
import com.minelittlepony.unicopia.datagen.providers.UBlockTagProvider;
import com.minelittlepony.unicopia.datagen.providers.UItemTagProvider;
import com.minelittlepony.unicopia.datagen.providers.UAdvancementsProvider;
import com.minelittlepony.unicopia.datagen.providers.UModelProvider;
import com.minelittlepony.unicopia.datagen.providers.URecipeProvider;
import com.minelittlepony.unicopia.datagen.providers.loot.UBlockAdditionsLootTableProvider;
import com.minelittlepony.unicopia.datagen.providers.loot.UBlockLootTableProvider;
import com.minelittlepony.unicopia.datagen.providers.loot.UChestAdditionsLootTableProvider;
import com.minelittlepony.unicopia.datagen.providers.loot.UChestLootTableProvider;
import com.minelittlepony.unicopia.datagen.providers.loot.UEntityLootTableProvider;
import com.minelittlepony.unicopia.datagen.providers.recipe.URecipeProvider;
import com.minelittlepony.unicopia.datagen.providers.tag.UBlockTagProvider;
import com.minelittlepony.unicopia.datagen.providers.tag.UDamageTypeProvider;
import com.minelittlepony.unicopia.datagen.providers.tag.UItemTagProvider;
import com.minelittlepony.unicopia.entity.damage.UDamageTypes;
import com.minelittlepony.unicopia.server.world.UWorldGen;
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryBuilder;
import net.minecraft.registry.RegistryEntryLookup;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.util.Identifier;
import net.minecraft.world.biome.OverworldBiomeCreator;
import net.minecraft.world.gen.carver.ConfiguredCarver;
import net.minecraft.world.gen.feature.PlacedFeature;
public class Datagen implements DataGeneratorEntrypoint {
public static final Logger LOGGER = LogManager.getLogger();
public static Block getOrCreateBaleBlock(Identifier id) {
return Registries.BLOCK.getOrEmpty(id).orElseGet(() -> {
return Registry.register(Registries.BLOCK, id, new EdibleBlock(id, id, false));
});
}
public static Item getOrCreateItem(Identifier id) {
return Registries.ITEM.getOrEmpty(id).orElseGet(() -> {
return Registry.register(Registries.ITEM, id, new Item(new Item.Settings()));
});
}
@Override
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
final FabricDataGenerator.Pack pack = fabricDataGenerator.createPack();
UBlockTagProvider blockTags = pack.addProvider(UBlockTagProvider::new);
pack.addProvider((output, registries) -> new UItemTagProvider(output, registries, blockTags));
final var pack = fabricDataGenerator.createPack();
final var blockTags = pack.addProvider(UBlockTagProvider::new);
final var itemTags = pack.addProvider((output, registries) -> new UItemTagProvider(output, registries, blockTags));
pack.addProvider((output, registries) -> new DietsProvider(output, itemTags));
pack.addProvider(UDamageTypeProvider::new);
pack.addProvider(UModelProvider::new);
pack.addProvider(URecipeProvider::new);
pack.addProvider(UBlockLootTableProvider::new);
pack.addProvider(UEntityLootTableProvider::new);
pack.addProvider(UChestLootTableProvider::new);
pack.addProvider(UBlockAdditionsLootTableProvider::new);
pack.addProvider(UChestAdditionsLootTableProvider::new);
pack.addProvider(SeasonsGrowthRatesProvider::new);
pack.addProvider(UAdvancementsProvider::new);
}
@Override
public void buildRegistry(RegistryBuilder builder) {
builder.addRegistry(RegistryKeys.BIOME, registerable -> {
RegistryEntryLookup<PlacedFeature> placedFeatureLookup = registerable.getRegistryLookup(RegistryKeys.PLACED_FEATURE);
RegistryEntryLookup<ConfiguredCarver<?>> carverLookup = registerable.getRegistryLookup(RegistryKeys.CONFIGURED_CARVER);
final var placedFeatureLookup = registerable.getRegistryLookup(RegistryKeys.PLACED_FEATURE);
final var carverLookup = registerable.getRegistryLookup(RegistryKeys.CONFIGURED_CARVER);
registerable.register(UWorldGen.SWEET_APPLE_ORCHARD, OverworldBiomeCreator.createNormalForest(placedFeatureLookup, carverLookup, false, false, false));
});
builder.addRegistry(RegistryKeys.DAMAGE_TYPE, UDamageTypes.REGISTRY);
}
}

View file

@ -19,4 +19,24 @@ public interface UBlockFamilies {
.slab(UBlocks.WAXED_ZAP_SLAB).stairs(UBlocks.WAXED_ZAP_STAIRS).fence(UBlocks.WAXED_ZAP_FENCE).fenceGate(UBlocks.WAXED_ZAP_FENCE_GATE)
.group("wooden").unlockCriterionName("has_planks")
.build();
BlockFamily CHISELED_CHITIN = new BlockFamily.Builder(UBlocks.CHISELLED_CHITIN)
.slab(UBlocks.CHISELLED_CHITIN_SLAB).stairs(UBlocks.CHISELLED_CHITIN_STAIRS)
.group("chitin").unlockCriterionName("has_chiselled_chitin")
.build();
BlockFamily CLOUD = new BlockFamily.Builder(UBlocks.CLOUD)
.slab(UBlocks.CLOUD_SLAB).stairs(UBlocks.CLOUD_STAIRS)
.group("cloud").unlockCriterionName("has_cloud_lump")
.build();
BlockFamily CLOUD_PLANKS = new BlockFamily.Builder(UBlocks.CLOUD_PLANKS)
.slab(UBlocks.CLOUD_PLANK_SLAB).stairs(UBlocks.CLOUD_PLANK_STAIRS)
.group("cloud").unlockCriterionName("has_cloud")
.build();
BlockFamily CLOUD_BRICKS = new BlockFamily.Builder(UBlocks.CLOUD_BRICKS)
.slab(UBlocks.CLOUD_BRICK_SLAB).stairs(UBlocks.CLOUD_BRICK_STAIRS)
.group("cloud").unlockCriterionName("has_cloud_bricks")
.build();
BlockFamily DENSE_CLOUD = new BlockFamily.Builder(UBlocks.DENSE_CLOUD)
.slab(UBlocks.DENSE_CLOUD_SLAB).stairs(UBlocks.DENSE_CLOUD_STAIRS)
.group("cloud").unlockCriterionName("has_dense_cloud")
.build();
}

View file

@ -0,0 +1,145 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Unicopia;
import net.minecraft.advancement.Advancement;
import net.minecraft.advancement.AdvancementCriterion;
import net.minecraft.advancement.AdvancementDisplay;
import net.minecraft.advancement.AdvancementEntry;
import net.minecraft.advancement.AdvancementFrame;
import net.minecraft.advancement.AdvancementRequirements;
import net.minecraft.advancement.AdvancementRewards;
import net.minecraft.item.ItemConvertible;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
public class AdvancementDisplayBuilder {
private static final Identifier BACKGROUND = new Identifier("textures/gui/advancements/backgrounds/stone.png");
public static AdvancementDisplayBuilder create(ItemConvertible icon) {
return new AdvancementDisplayBuilder(icon, Advancement.Builder.create(), false, false, false);
}
@Nullable
private Identifier background = BACKGROUND;
private boolean toast;
private boolean hidden;
private boolean announce;
private final ItemConvertible icon;
private AdvancementFrame frame = AdvancementFrame.TASK;
@Nullable
private String group;
private final Advancement.Builder advancementBuilder;
AdvancementDisplayBuilder(ItemConvertible icon, Advancement.Builder advancementBuilder, boolean toast, boolean announce, boolean hidden) {
this.icon = icon;
this.advancementBuilder = advancementBuilder;
this.toast = toast;
this.announce = announce;
this.hidden = hidden;
}
public AdvancementDisplayBuilder frame(AdvancementFrame frame) {
this.frame = frame;
return this;
}
public AdvancementDisplayBuilder background(Identifier background) {
this.background = background;
return this;
}
public AdvancementDisplayBuilder showToast() {
this.toast = true;
return this;
}
public AdvancementDisplayBuilder hidden() {
this.hidden = true;
return this;
}
public AdvancementDisplayBuilder visible() {
this.hidden = false;
return this;
}
public AdvancementDisplayBuilder announce() {
this.announce = true;
return this;
}
public AdvancementDisplayBuilder doNotAnnounce() {
this.announce = false;
return this;
}
public AdvancementDisplayBuilder group(String group) {
this.group = group;
return this;
}
public AdvancementDisplayBuilder rewards(AdvancementRewards.Builder builder) {
advancementBuilder.rewards(builder.build());
return this;
}
public AdvancementDisplayBuilder criterion(String name, AdvancementCriterion<?> criterion) {
advancementBuilder.criterion(name, criterion);
return this;
}
public AdvancementDisplayBuilder criteriaMerger(AdvancementRequirements.CriterionMerger merger) {
advancementBuilder.criteriaMerger(merger);
return this;
}
public AdvancementDisplayBuilder parent(Identifier parent) {
advancementBuilder.parent(Advancement.Builder.createUntelemetered().build(parent));
return this;
}
public AdvancementDisplayBuilder apply(Consumer<AdvancementDisplayBuilder> consumer) {
consumer.accept(this);
return this;
}
public Parent build(Consumer<AdvancementEntry> exporter, String name) {
Identifier id = Unicopia.id(group == null ? name : group + "/" + name);
String key = Util.createTranslationKey("advancements", Unicopia.id(name));
AdvancementEntry advancement = advancementBuilder.display(
icon.asItem().getDefaultStack(),
Text.translatable(key + ".title"),
Text.translatable(key + ".description"), background, frame, toast, announce, hidden)
.build(id);
exporter.accept(advancement);
return new Parent(advancement, group);
}
public record Parent(AdvancementEntry parent, @Nullable String group) {
public AdvancementDisplayBuilder child(ItemConvertible icon) {
AdvancementDisplay display = parent.value().display().orElseThrow();
return new AdvancementDisplayBuilder(icon, Advancement.Builder.create().parent(parent),
display.shouldShowToast(),
display.shouldAnnounceToChat(),
display.isHidden()
).frame(display.getFrame()).background(display.getBackground().orElse(null)).group(group);
}
public void children(Consumer<Parent> children) {
children.accept(this);
}
public void children(Consumer<AdvancementEntry> exporter, BiConsumer<Consumer<AdvancementEntry>, Parent> children) {
children.accept(exporter, this);
}
}
}

View file

@ -34,6 +34,7 @@ public interface BlockModels {
Model DOOR_RIGHT = block("door_right", TextureKey.BOTTOM, TextureKey.TOP);
Model TEMPLATE_PILLAR = block("template_pillar", TextureKey.SIDE);
Model TEMPLATE_PILLAR_END = block("template_pillar_end", "_end", TextureKey.BOTTOM, TextureKey.TOP, TextureKey.END);
Identifier TEMPLATE_JAR = Unicopia.id("block/template_jar");
Factory CROP = Factory.of(TextureMap::crop, Models.CROP);
Factory CUBE_ALL = Factory.of(TextureMap::all, Models.CUBE_ALL);

View file

@ -0,0 +1,275 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.diet.DietProfile;
import com.minelittlepony.unicopia.diet.DietProfile.Multiplier;
import com.minelittlepony.unicopia.diet.FoodGroupEffects;
import com.minelittlepony.unicopia.diet.affliction.ClearLoveSicknessAffliction;
import com.minelittlepony.unicopia.diet.affliction.CompoundAffliction;
import com.minelittlepony.unicopia.diet.affliction.HealingAffliction;
import com.minelittlepony.unicopia.diet.affliction.LoseHungerAffliction;
import com.minelittlepony.unicopia.diet.affliction.Range;
import com.minelittlepony.unicopia.diet.affliction.StatusEffectAffliction;
import com.minelittlepony.unicopia.entity.effect.UEffects;
import com.minelittlepony.unicopia.item.UFoodComponents;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.FoodComponents;
public class DietProfileGenerator {
public void generate(BiConsumer<Race, DietProfile> exporter) {
// Pinecones are for everypony
var pineconeMultiplier = new Multiplier.Builder().tag(Unicopia.id("pinecone")).hunger(0.9F).saturation(0.9F).build();
var bakedGoodPreference = new Multiplier.Builder().tag(Unicopia.id("baked_goods")).build();
var bakedGoodExtremePreference = new Multiplier.Builder().tag(Unicopia.id("baked_goods")).hunger(1.2F).saturation(2).build();
var bakedGoodNonPreference = new Multiplier.Builder().tag(Unicopia.id("baked_goods")).hunger(0.4F).saturation(0.2F).build();
var properMeatStandards = new Multiplier.Builder().tag(Unicopia.id("love"))
.tag(Unicopia.id("meat/raw")).tag(Unicopia.id("insect/raw")).tag(Unicopia.id("fish/raw"))
.tag(Unicopia.id("meat/rotten")).tag(Unicopia.id("insect/rotten")).tag(Unicopia.id("fish/rotten"))
.hunger(0).saturation(0).build();
var avianMeatStandards = new Multiplier.Builder().tag(Unicopia.id("love"))
.tag(Unicopia.id("meat/raw")).tag(Unicopia.id("insect/raw"))
.tag(Unicopia.id("meat/rotten")).tag(Unicopia.id("insect/rotten"))
.hunger(0).saturation(0).build();
var loveSicknessEffects = CompoundAffliction.of(
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 95),
new StatusEffectAffliction(StatusEffects.WEAKNESS, Range.of(200), Range.of(1), 0),
new LoseHungerAffliction(0.5F));
var seaFoodExclusions = new Multiplier.Builder()
.tag(Unicopia.id("sea_vegetable/raw")).tag(Unicopia.id("sea_vegetable/cooked"))
.tag(Unicopia.id("shells")).tag(Unicopia.id("special_shells"))
.hunger(0).saturation(0).build();
exporter.accept(Race.HUMAN, new DietProfile(1, 0, List.of(), List.of(
new FoodGroupEffects.Builder()
.tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).tag(Unicopia.id("fish/rotten"))
.tag(Unicopia.id("meat/cooked")).tag(Unicopia.id("meat/raw")).tag(Unicopia.id("meat/rotten"))
.tag(Unicopia.id("sea_vegetable/cooked")).tag(Unicopia.id("sea_vegetable/raw"))
.tag(Unicopia.id("pinecone"))
.build()
), Optional.empty()));
// Alicorns are a mashup of unicorn, pegasus, and earth pony eating habits
exporter.accept(Race.ALICORN, new DietProfile(0.9F, 1, List.of(
// Pastries are their passion
bakedGoodExtremePreference, pineconeMultiplier, avianMeatStandards, seaFoodExclusions,
// They have a more of a sweet tooth than earth ponies
new Multiplier.Builder().tag(Unicopia.id("desserts")).hunger(2.5F).saturation(1.7F).build(),
new Multiplier.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("rocks")).hunger(1.5F).saturation(1.3F).build(),
// Cannot eat love, or raw/rotten meats and fish
// Can eat raw and rotten fish but still prefers if they are cooked
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(1.5F).saturation(1.5F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.25F).saturation(0.16F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.7F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.5F).saturation(0.8F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.25F).saturation(0.5F).build()
), List.of(
// Can safely eat fresh and cooked fish with no ill effects
new FoodGroupEffects.Builder().tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).build(),
// Is less affected when eating rotten fish
new FoodGroupEffects.Builder().tag(Unicopia.id("fish/rotten")).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(50), Range.of(2), 95)).build()
), Optional.empty()));
// Unicorns have a general even preference of foods
exporter.accept(Race.UNICORN, new DietProfile(1.1F, 1, List.of(
bakedGoodPreference, pineconeMultiplier, seaFoodExclusions,
new Multiplier.Builder().tag(Unicopia.id("love")).hunger(0).saturation(0).build(),
// Improved benefits from cooking their food
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.3F).saturation(0.2F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.4F).saturation(0.4F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.1F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.25F).saturation(0.1F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/raw")).hunger(0.3F).saturation(0.1F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/raw")).hunger(0.15F).saturation(0.1F).build(),
// Can still eat raw and rotten but at a reduced yield
new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.1F).saturation(0.1F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/rotten")).hunger(0.1F).saturation(0.1F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/rotten")).hunger(0).saturation(0.1F).build()
), List.of(), Optional.empty()));
// Bats prefer cooked foods over raw, and meat/insects over fish
exporter.accept(Race.BAT, new DietProfile(0.7F, 0.9F, List.of(
pineconeMultiplier, seaFoodExclusions,
// Doesn't like baked goods but really likes meats, fish, and insects
bakedGoodNonPreference,
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.75F).saturation(0.75F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(1.15F).saturation(1.16F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(1.75F).saturation(1.74F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.5F).saturation(0.6F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/raw")).hunger(0.25F).saturation(0.25F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/raw")).hunger(1).saturation(1).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.24F).saturation(0.25F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/rotten")).hunger(0.2F).saturation(0.2F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/rotten")).hunger(0.9F).saturation(0.9F).build()
), List.of(
// Gets food poisoning from eating rotten and raw meat
new FoodGroupEffects.Builder().tag(Unicopia.id("fish/rotten")).tag(Unicopia.id("meat/raw")).tag(Unicopia.id("meat/rotten")).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 5)).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("insect/rotten")).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(50), Range.of(1), 15)).build(),
// Can eat cooked meat and insects without negative effects
new FoodGroupEffects.Builder().tag(Unicopia.id("insect/cooked")).tag(Unicopia.id("meat/cooked")).build(),
// Becomes hyper when eating mangoes
new FoodGroupEffects.Builder().tag(Unicopia.id("bat_ponys_delight")).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.HEALTH_BOOST, Range.of(30, 60), Range.of(2, 6), 0),
new StatusEffectAffliction(StatusEffects.JUMP_BOOST, Range.of(30, 60), Range.of(1, 6), 0),
new StatusEffectAffliction(StatusEffects.REGENERATION, Range.of(3, 30), Range.of(3, 6), 0)
)).build()
), Optional.empty()));
// Much like Earth Ponies, Kirins must cook their meat before they eat it
exporter.accept(Race.KIRIN, new DietProfile(0.6F, 0.9F, List.of(
// Cannot eat love, or raw/rotten meats and fish
bakedGoodPreference, properMeatStandards, pineconeMultiplier, seaFoodExclusions,
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.75F).saturation(0.35F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(1.5F).saturation(1.6F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.25F).saturation(0.74F).build()
), List.of(
// can eat these without negative effects
new FoodGroupEffects.Builder().tag(Unicopia.id("insect/cooked")).tag(Unicopia.id("meat/cooked")).food(FoodComponents.COOKED_BEEF).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/blinding")).food(4, 0.2F).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/prickly")).food(0, 1.5F).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/severely_prickly")).food(2, 0.9F).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/strengthening")).food(4, 0.2F).ailment(new StatusEffectAffliction(StatusEffects.STRENGTH, Range.of(1300), Range.of(0), 0)).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("foraging/glowing")).food(1, 1.6F).ailment(new StatusEffectAffliction(StatusEffects.GLOWING, Range.of(30), Range.of(0), 30)).build()
), Optional.empty()));
// Earth Ponies are vegans. They get the most from foraging
exporter.accept(Race.EARTH, new DietProfile(0.7F, 1.2F, List.of(
// Pastries are their passion
// If they must eat meat, they have to cook it and not let it spoil.
bakedGoodExtremePreference, pineconeMultiplier, properMeatStandards, seaFoodExclusions,
// They have a sweet tooth
new Multiplier.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("desserts")).tag(Unicopia.id("rocks")).hunger(2.5F).saturation(1.7F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.2F).saturation(0.3F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.1F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.1F).saturation(0.1F).build()
), List.of(
// Candy and rocks gives them a massive saturation boost. Maybe too much?
new FoodGroupEffects.Builder().tag(Unicopia.id("candy")).tag(Unicopia.id("rocks")).food(UFoodComponents.builder(5, 12).alwaysEdible()).build(),
new FoodGroupEffects.Builder().tag(Unicopia.id("desserts")).food(UFoodComponents.builder(12, 32).snack().alwaysEdible()).build()
), Optional.empty()));
// Pegasi prefer fish over other food sources
exporter.accept(Race.PEGASUS, new DietProfile(0.9F, 1, List.of(
bakedGoodPreference, pineconeMultiplier, avianMeatStandards, seaFoodExclusions,
// Cannot eat love, or raw/rotten meat
// Can eat raw and rotten fish but still prefers if they are cooked
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(1.5F).saturation(1.5F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.25F).saturation(0.16F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(0.1F).saturation(0.7F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.5F).saturation(0.8F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.25F).saturation(0.5F).build()
), List.of(
// Can safely eat fresh and cooked fish with no ill effects
new FoodGroupEffects.Builder().tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).build(),
// Is less affected when eating rotten fish
new FoodGroupEffects.Builder().tag(Unicopia.id("fish/rotten")).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(50), Range.of(2), 95)).build()
), Optional.empty()));
// Changelings like meat and fish but really prefer feasting on ponies' love directly from the tap
exporter.accept(Race.CHANGELING, new DietProfile(0.15F, 0.1F, List.of(
// Doesn't like baked goods but really likes meats, fish, and insects
bakedGoodNonPreference, pineconeMultiplier, seaFoodExclusions,
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(0.5F).saturation(1.2F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(0.9F).saturation(1.2F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/cooked")).hunger(1.2F).saturation(1.3F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.15F).saturation(0.25F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/raw")).hunger(1.25F).saturation(1.25F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/raw")).hunger(1).saturation(1).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.24F).saturation(0.25F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/rotten")).hunger(0.2F).saturation(0.2F).build(),
new Multiplier.Builder().tag(Unicopia.id("insect/rotten")).hunger(0.9F).saturation(0.9F).build(),
new Multiplier.Builder().tag(Unicopia.id("love")).hunger(1).saturation(1.5F).build()
), List.of(
// Can eat fish, meat, insects, and love without negative effects
new FoodGroupEffects.Builder()
.tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("meat/cooked")).tag(Unicopia.id("insect/cooked"))
.tag(Unicopia.id("fish/rotten")).tag(Unicopia.id("meat/rotten")).tag(Unicopia.id("insect/rotten"))
.tag(Unicopia.id("fish/raw")).tag(Unicopia.id("meat/raw")).tag(Unicopia.id("insect/raw"))
.tag(Unicopia.id("baked_goods")).tag(Unicopia.id("pinecone"))
.tag(Unicopia.id("love")).ailment(ClearLoveSicknessAffliction.INSTANCE).build(),
new FoodGroupEffects.Builder()
.tag(Unicopia.id("foraging/blinding")).tag(Unicopia.id("foraging/dangerous")).tag(Unicopia.id("foraging/edible_filling"))
.tag(Unicopia.id("foraging/edible")).tag(Unicopia.id("foraging/leafy_greens")).tag(Unicopia.id("foraging/nauseating"))
.tag(Unicopia.id("foraging/prickly")).tag(Unicopia.id("foraging/glowing")).tag(Unicopia.id("foraging/risky"))
.tag(Unicopia.id("foraging/severely_nauseating")).tag(Unicopia.id("foraging/severely_prickly"))
.tag(Unicopia.id("foraging/strengthening"))
.ailment(loveSicknessEffects)
.build()
), Optional.empty()));
// Hippogriffs like fish, nuts, and seeds
exporter.accept(Race.HIPPOGRIFF, new DietProfile(0.5F, 0.8F, List.of(
bakedGoodPreference, pineconeMultiplier, seaFoodExclusions,
new Multiplier.Builder().tag(Unicopia.id("love"))
.tag(Unicopia.id("insect/cooked")).tag(Unicopia.id("insect/raw")).tag(Unicopia.id("insect/rotten"))
.hunger(0).saturation(0).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(1.5F).saturation(1.2F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/cooked")).hunger(1.9F).saturation(1.2F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.85F).saturation(0.95F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/raw")).hunger(0.75F).saturation(0.75F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.24F).saturation(0.25F).build(),
new Multiplier.Builder().tag(Unicopia.id("meat/rotten")).hunger(0.3F).saturation(0.5F).build(),
new Multiplier.Builder().tag(Unicopia.id("nuts_and_seeds")).hunger(1.4F).saturation(1.4F).build()
), List.of(
// Can eat fish and prickly foods without negative effect
new FoodGroupEffects.Builder()
.tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).tag(Unicopia.id("fish/rotten"))
.tag(Unicopia.id("foraging/prickly")).tag(Unicopia.id("foraging/severely_prickly"))
.build(),
// Gains more health from pinecones
new FoodGroupEffects.Builder().tag(Unicopia.id("pinecone")).ailment(new HealingAffliction(3)).build()
), Optional.empty()));
// Seaponies can eat seaweed, kelp, shells, and other undersea foods
exporter.accept(Race.SEAPONY, new DietProfile(0.5F, 0.8F, List.of(
new Multiplier.Builder().tag(Unicopia.id("fish/cooked")).hunger(1.5F).saturation(1.2F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/raw")).hunger(0.85F).saturation(0.95F).build(),
new Multiplier.Builder().tag(Unicopia.id("fish/rotten")).hunger(0.24F).saturation(0.25F).build(),
new Multiplier.Builder()
.tag(Unicopia.id("sea_vegetable/raw"))
.tag(Unicopia.id("sea_vegetable/cooked"))
.tag(Unicopia.id("shells")).tag(Unicopia.id("special_shells"))
.hunger(1).saturation(1).build()
), List.of(
// Can eat fish without negative effect
new FoodGroupEffects.Builder()
.tag(Unicopia.id("fish/cooked")).tag(Unicopia.id("fish/raw")).tag(Unicopia.id("fish/rotten"))
.build(),
// Gains more health from pinecones
new FoodGroupEffects.Builder().tag(Unicopia.id("pinecone")).ailment(new HealingAffliction(3)).build()
), Optional.empty()));
}
}

View file

@ -0,0 +1,83 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.datagen.DataCollector;
import com.minelittlepony.unicopia.diet.DietProfile;
import com.minelittlepony.unicopia.diet.FoodGroup;
import com.mojang.serialization.JsonOps;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.minecraft.data.DataOutput;
import net.minecraft.data.DataProvider;
import net.minecraft.data.DataWriter;
import net.minecraft.data.server.tag.TagProvider;
import net.minecraft.data.server.tag.TagProvider.TagLookup;
import net.minecraft.item.Item;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public class DietsProvider implements DataProvider {
private final DataCollector dietsCollector;
private final DataCollector categoriesCollector;
private final CompletableFuture<TagLookup<Item>> itemTagLookup;
public DietsProvider(FabricDataOutput output, TagProvider<Item> tagProvider) {
this.dietsCollector = new DataCollector(output.getResolver(DataOutput.OutputType.DATA_PACK, "diet/races"));
this.categoriesCollector = new DataCollector(output.getResolver(DataOutput.OutputType.DATA_PACK, "diet/food_groups"));
itemTagLookup = tagProvider.getTagLookupFuture();
}
@Override
public String getName() {
return "Diets";
}
@Override
public CompletableFuture<?> run(DataWriter writer) {
return itemTagLookup.thenCompose(tagLookup -> {
var diets = categoriesCollector.prime();
Map<Identifier, Set<Identifier>> keyToGroupId = new HashMap<>();
new FoodGroupsGenerator().generate((id, builder) -> {
var attributes = builder.build();
attributes.tags().forEach(key -> {
if (!tagLookup.contains(TagKey.of(RegistryKeys.ITEM, key.id()))) {
throw new IllegalArgumentException("Food group " + id + " references unknown item tag " + key.id());
}
keyToGroupId.computeIfAbsent(key.id(), i -> new HashSet<>()).add(id);
});
diets.accept(id, () -> FoodGroup.CODEC.encode(attributes, JsonOps.INSTANCE, new JsonObject()).result().get());
});
var profiles = dietsCollector.prime();
new DietProfileGenerator().generate((race, profile) -> {
Identifier id = Race.REGISTRY.getId(race);
StringBuilder issues = new StringBuilder();
profile.validate(issue -> {
issues.append(System.lineSeparator()).append(issue);
}, categoriesCollector::isDefined);
if (!issues.isEmpty()) {
throw new IllegalArgumentException("Diet profile " + id + " failed validation: " + issues.toString());
}
profiles.accept(id, () -> DietProfile.CODEC.encode(profile, JsonOps.INSTANCE, new JsonObject()).result().get());
});
keyToGroupId.forEach((tag, groups) -> {
if (groups.size() > 1) {
throw new IllegalArgumentException("Multiple groups referenced the same tag " + tag + " held by "
+ groups.stream().map(Identifier::toString).collect(Collectors.joining())
);
}
});
return CompletableFuture.allOf(categoriesCollector.upload(writer), dietsCollector.upload(writer));
});
}
}

View file

@ -0,0 +1,115 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.List;
import java.util.function.BiConsumer;
import com.minelittlepony.unicopia.UConventionalTags;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.diet.FoodGroupEffects;
import com.minelittlepony.unicopia.diet.affliction.Affliction;
import com.minelittlepony.unicopia.diet.affliction.CompoundAffliction;
import com.minelittlepony.unicopia.diet.affliction.HealingAffliction;
import com.minelittlepony.unicopia.diet.affliction.LoseHungerAffliction;
import com.minelittlepony.unicopia.diet.affliction.Range;
import com.minelittlepony.unicopia.diet.affliction.StatusEffectAffliction;
import com.minelittlepony.unicopia.entity.effect.UEffects;
import com.minelittlepony.unicopia.item.UFoodComponents;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.FoodComponent;
import net.minecraft.item.FoodComponents;
import net.minecraft.item.Item;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public class FoodGroupsGenerator {
public void generate(BiConsumer<Identifier, FoodGroupEffects.Builder> exporter) {
exporter.accept(Unicopia.id("baked_goods"), new FoodGroupEffects.Builder().tag(UTags.Items.BAKED_GOODS).food(FoodComponents.BREAD));
exporter.accept(Unicopia.id("bat_ponys_delight"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.MANGOES).food(UFoodComponents.MANGO));
exporter.accept(Unicopia.id("candy"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.CANDY).food(UFoodComponents.CANDY));
exporter.accept(Unicopia.id("desserts"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.DESSERTS).food(FoodComponents.COOKIE));
exporter.accept(Unicopia.id("fruit"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.FRUITS).food(UFoodComponents.BANANA));
exporter.accept(Unicopia.id("rocks"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.ROCKS).tag(UTags.Items.ROCK_STEWS).food(FoodComponents.MUSHROOM_STEW));
exporter.accept(Unicopia.id("shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SHELLS).food(UFoodComponents.SHELL));
exporter.accept(Unicopia.id("special_shells"), new FoodGroupEffects.Builder().tag(UTags.Items.SPECIAL_SHELLS).food(UFoodComponents.SHELLY));
exporter.accept(Unicopia.id("love"), new FoodGroupEffects.Builder().tag(UTags.Items.CONTAINER_WITH_LOVE).food(UFoodComponents.LOVE_MUG).ailment(new CompoundAffliction(List.<Affliction>of(
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(50), Range.of(2), 0),
new LoseHungerAffliction(0.5F)
))));
exporter.accept(Unicopia.id("nuts_and_seeds"), new FoodGroupEffects.Builder()
.tag(UConventionalTags.Items.GRAIN).tag(UConventionalTags.Items.NUTS).tag(UConventionalTags.Items.SEEDS)
.food(UFoodComponents.BANANA)
);
exporter.accept(Unicopia.id("pinecone"), new FoodGroupEffects.Builder().tag(UConventionalTags.Items.PINECONES).food(UFoodComponents.PINECONE).ailment(new HealingAffliction(1)));
provideMeatCategory("fish",
UConventionalTags.Items.COOKED_FISH, UConventionalTags.Items.RAW_FISH, UConventionalTags.Items.ROTTEN_FISH,
FoodComponents.COOKED_COD, FoodComponents.COD, FoodComponents.ROTTEN_FLESH, exporter);
provideMeatCategory("meat",
UConventionalTags.Items.COOKED_MEAT, UConventionalTags.Items.RAW_MEAT, UConventionalTags.Items.ROTTEN_MEAT,
FoodComponents.COOKED_BEEF, FoodComponents.BEEF, FoodComponents.ROTTEN_FLESH, exporter);
provideMeatCategory("insect",
UConventionalTags.Items.COOKED_INSECT, UConventionalTags.Items.RAW_INSECT, UConventionalTags.Items.ROTTEN_INSECT,
FoodComponents.COOKED_BEEF, FoodComponents.BEEF, FoodComponents.ROTTEN_FLESH, exporter);
provideVegetableCategory("sea_vegetable",
UTags.Items.HIGH_QUALITY_SEA_VEGETABLES, UTags.Items.LOW_QUALITY_SEA_VEGETABLES,
FoodComponents.COOKED_BEEF, FoodComponents.BEEF, exporter);
exporter.accept(Unicopia.id("foraging/blinding"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_BLINDING).food(4, 0.2F).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.BLINDNESS, Range.of(30), Range.of(0), 50),
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 12)
)));
exporter.accept(Unicopia.id("foraging/dangerous"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_DANGEROUS).food(3, 0.3F).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(250), Range.of(2), 4)));
exporter.accept(Unicopia.id("foraging/edible_filling"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_FILLING).food(17, 0.6F));
exporter.accept(Unicopia.id("foraging/edible"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SAFE).food(2, 1));
exporter.accept(Unicopia.id("foraging/leafy_greens"), new FoodGroupEffects.Builder().tag(ItemTags.LEAVES).food(1, 1.4F));
exporter.accept(Unicopia.id("foraging/nauseating"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_NAUSEATING).food(5, 0.5F).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.WEAKNESS, Range.of(200), Range.of(1), 30),
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(200), Range.of(2), 0)
)));
exporter.accept(Unicopia.id("foraging/prickly"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_PRICKLY).food(0, 1.5F).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.INSTANT_DAMAGE, Range.of(1), Range.of(0), 30)
)));
exporter.accept(Unicopia.id("foraging/glowing"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_GLOWING).food(1, 1.6F).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.GLOWING, Range.of(30), Range.of(0), 30),
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 0)
)));
exporter.accept(Unicopia.id("foraging/risky"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_RISKY).food(9, 1.1F).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80)));
exporter.accept(Unicopia.id("foraging/severely_nauseating"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SEVERE_NAUSEATING).food(3, 0.9F).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.WEAKNESS, Range.of(200), Range.of(1), 0),
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80)
)));
exporter.accept(Unicopia.id("foraging/severely_prickly"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_SEVERE_PRICKLY).food(2, 0.9F).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.INSTANT_DAMAGE, Range.of(1), Range.of(0), 0),
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 80)
)));
exporter.accept(Unicopia.id("foraging/strengthening"), new FoodGroupEffects.Builder().tag(UTags.Items.FORAGE_STRENGHENING).food(4, 0.2F).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.STRENGTH, Range.of(1300), Range.of(0), 0),
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 70)
)));
}
private void provideMeatCategory(String name,
TagKey<Item> cookedTag, TagKey<Item> rawTag, TagKey<Item> rottenTag,
FoodComponent cooked, FoodComponent raw, FoodComponent rotten,
BiConsumer<Identifier, FoodGroupEffects.Builder> exporter) {
exporter.accept(Unicopia.id(name + "/cooked"), new FoodGroupEffects.Builder().tag(cookedTag).food(cooked).ailment(new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 25)));
exporter.accept(Unicopia.id(name + "/raw"), new FoodGroupEffects.Builder().tag(rawTag).food(raw).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.POISON, Range.of(45), Range.of(2), 80),
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 65)
)));
exporter.accept(Unicopia.id(name + "/rotten"), new FoodGroupEffects.Builder().tag(rottenTag).food(rotten).ailment(CompoundAffliction.of(
new StatusEffectAffliction(StatusEffects.POISON, Range.of(45), Range.of(2), 80),
new StatusEffectAffliction(UEffects.FOOD_POISONING, Range.of(100), Range.of(2), 95)
)));
}
private void provideVegetableCategory(String name,
TagKey<Item> cookedTag, TagKey<Item> rawTag,
FoodComponent cooked, FoodComponent raw,
BiConsumer<Identifier, FoodGroupEffects.Builder> exporter) {
exporter.accept(Unicopia.id(name + "/cooked"), new FoodGroupEffects.Builder().tag(cookedTag).food(cooked));
exporter.accept(Unicopia.id(name + "/raw"), new FoodGroupEffects.Builder().tag(rawTag).food(raw));
}
}

View file

@ -12,17 +12,16 @@ import com.minelittlepony.unicopia.server.world.UTreeGen;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.minecraft.block.Block;
import net.minecraft.data.DataOutput;
import net.minecraft.data.DataOutput.PathResolver;
import net.minecraft.registry.Registries;
import net.minecraft.data.DataProvider;
import net.minecraft.data.DataWriter;
public class SeasonsGrowthRatesProvider implements DataProvider {
private final PathResolver pathResolver;
private final DataCollector collectedData;
public SeasonsGrowthRatesProvider(FabricDataOutput output) {
this.pathResolver = output.getResolver(DataOutput.OutputType.DATA_PACK, "seasons/crop");
this.collectedData = new DataCollector(output.getResolver(DataOutput.OutputType.DATA_PACK, "seasons/crop"));
}
@Override
@ -32,7 +31,6 @@ public class SeasonsGrowthRatesProvider implements DataProvider {
@Override
public CompletableFuture<?> run(DataWriter writer) {
DataCollector collectedData = new DataCollector(pathResolver);
var exporter = collectedData.prime();
generate((block, crop) -> {
exporter.accept(Registries.BLOCK.getId(block), crop::toJson);

View file

@ -0,0 +1,272 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.advancement.CustomEventCriterion;
import com.minelittlepony.unicopia.advancement.RaceChangeCriterion;
import com.minelittlepony.unicopia.advancement.RacePredicate;
import com.minelittlepony.unicopia.advancement.SendViaDragonBreathScrollCriterion;
import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricAdvancementProvider;
import net.fabricmc.fabric.api.util.TriState;
import net.minecraft.advancement.AdvancementCriterion;
import net.minecraft.advancement.AdvancementEntry;
import net.minecraft.advancement.AdvancementFrame;
import net.minecraft.advancement.AdvancementRequirements;
import net.minecraft.advancement.AdvancementRewards;
import net.minecraft.advancement.criterion.ConsumeItemCriterion;
import net.minecraft.advancement.criterion.Criteria;
import net.minecraft.advancement.criterion.EnchantedItemCriterion;
import net.minecraft.advancement.criterion.InventoryChangedCriterion;
import net.minecraft.advancement.criterion.OnKilledCriterion;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.damage.DamageType;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.Items;
import net.minecraft.predicate.NumberRange;
import net.minecraft.predicate.TagPredicate;
import net.minecraft.predicate.entity.DamageSourcePredicate;
import net.minecraft.predicate.item.EnchantmentPredicate;
import net.minecraft.predicate.item.ItemPredicate;
import net.minecraft.registry.Registries;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public class UAdvancementsProvider extends FabricAdvancementProvider {
public UAdvancementsProvider(FabricDataOutput output) {
super(output);
}
@Override
public void generateAdvancement(Consumer<AdvancementEntry> consumer) {
AdvancementDisplayBuilder.create(UItems.ALICORN_BADGE).criterion("crafting_table", hasItems(Items.CRAFTING_TABLE)).build(consumer, "root").children(root -> {
createTribeRootAdvancement(consumer, root, Race.EARTH).children(consumer, this::generateEarthTribeAdvancementsTree);
createTribeRootAdvancement(consumer, root, Race.BAT).children(consumer, this::generateBatTribeAdvancementsTree);
createTribeRootAdvancement(consumer, root, Race.PEGASUS).children(consumer, this::generatePegasusTribeAdvancementsTree);
createTribeRootAdvancement(consumer, root, Race.UNICORN, Race.ALICORN).children(consumer, this::generateUnicornTribeAdvancementsTree);
createTribeRootAdvancement(consumer, root, Race.HIPPOGRIFF, Race.SEAPONY).children(consumer, this::generateHippogrifTribeAdvancementsTree);
});
generateEnchantmentsAdvancementsTree(consumer);
}
private AdvancementDisplayBuilder.Parent createTribeRootAdvancement(Consumer<AdvancementEntry> consumer, AdvancementDisplayBuilder.Parent root, Race race, Race...extra) {
AdvancementDisplayBuilder builder = root.child(Registries.ITEM.get(race.getId().withSuffixedPath("_badge"))).showToast().announce().group(race.getId().getPath())
.criterion("be_" + race.getId().getPath(), UCriteria.PLAYER_CHANGE_RACE.create(new RaceChangeCriterion.Conditions(Optional.empty(), race)));
if (extra.length > 0) {
for (Race r : extra) {
builder.criterion("be_" + r.getId().getPath(), UCriteria.PLAYER_CHANGE_RACE.create(new RaceChangeCriterion.Conditions(Optional.empty(), r)));
}
}
return builder.build(consumer, race.getId().getPath() + "_route");
}
private void generateEarthTribeAdvancementsTree(Consumer<AdvancementEntry> consumer, AdvancementDisplayBuilder.Parent parent) {
parent.child(UItems.ROCK).criterion("has_rock", hasItems(UItems.ROCK)).build(consumer, "born_on_a_rock_farm").children(p -> {
p.child(UItems.PEBBLES).criterion("killed_entity_with_rock", killWithItems(UTags.DamageTypes.FROM_ROCKS)).build(consumer, "sticks_and_stones");
p.child(UItems.WEIRD_ROCK).hidden().criterion("has_rock", hasItems(UItems.WEIRD_ROCK)).build(consumer, "thats_unusual");
});
parent.child(UItems.FRIED_AXOLOTL).criterion("eaten_axolotl", ConsumeItemCriterion.Conditions.item(UItems.FRIED_AXOLOTL)).build(consumer, "tastes_like_chicken");
parent.child(UItems.OATS).criterion("has_oats", hasItems(UItems.OATS)).build(consumer, "oats_so_easy");
parent.child(Items.HAY_BLOCK).criterion("eat_hay", ConsumeItemCriterion.Conditions.item(Items.HAY_BLOCK)).build(consumer, "what_the_hay");
parent.child(UItems.COPPER_HORSE_SHOE).criterion("has_horseshoe", hasItems(UTags.Items.HORSE_SHOES)).build(consumer, "blacksmith").children(p -> {
p.child(UItems.IRON_HORSE_SHOE).criterion("has_iron_horseshoe", hasItems(UItems.IRON_HORSE_SHOE)).build(consumer, "change_of_shoes")
.child(UItems.GOLDEN_HORSE_SHOE).criterion("has_gold_horseshoe", hasItems(UItems.GOLDEN_HORSE_SHOE)).build(consumer, "fashionably_expensive")
.child(UItems.NETHERITE_HORSE_SHOE).criterion("has_netherite_horseshoe", hasItems(UItems.NETHERITE_HORSE_SHOE)).build(consumer, "overkill");
p.child(UItems.IRON_HORSE_SHOE).hidden().frame(AdvancementFrame.CHALLENGE).criterion("killed_entity_with_horseshoe", killWithItems(UTags.DamageTypes.FROM_HORSESHOES)).build(consumer, "dead_ringer");
});
parent.child(UItems.PINECONE).frame(AdvancementFrame.CHALLENGE).criterion("eat_pinecone", ConsumeItemCriterion.Conditions.item(UItems.PINECONE)).build(consumer, "eat_pinecone");
parent.child(UItems.OAK_BASKET).doNotAnnounce().criterion("has_basket", hasItems(UTags.Items.BASKETS)).build(consumer, "basket_case")
.child(Items.LANTERN).criterion("construct_balloon", CustomEventCriterion.create("construct_balloon")).build(consumer, "aeronaut")
.child(UItems.GIANT_BALLOON).announce().frame(AdvancementFrame.CHALLENGE).criterion("ride_balloon", CustomEventCriterion.create("ride_balloon")).build(consumer, "travelling_in_style");
parent.child(UItems.MUFFIN).hidden().criterion("has_muffin", hasItems(UItems.MUFFIN)).build(consumer, "baked_bads");
parent.child(UItems.HORSE_SHOE_FRIES).criterion("has_horse_shoe_fries", hasItems(UItems.HORSE_SHOE_FRIES)).build(consumer, "lucky");
parent.child(UItems.TOAST).criterion("has_toast", hasItems(UItems.TOAST)).build(consumer, "toast")
.child(UItems.BURNED_TOAST).hidden().criterion("has_burned_toast", hasItems(UItems.BURNED_TOAST)).build(consumer, "burn_toast");
parent.child(UItems.GREEN_APPLE).criterion("has_apple", hasItems(UTags.Items.FRESH_APPLES)).build(consumer, "apple_route").children(p -> {
p.child(UItems.SWEET_APPLE).criterion("has_all_apples", hasItems(Items.APPLE, UItems.GREEN_APPLE, UItems.SWEET_APPLE, UItems.SOUR_APPLE, UItems.ROTTEN_APPLE, UItems.ZAP_APPLE, UItems.COOKED_ZAP_APPLE, Items.GOLDEN_APPLE)).build(consumer, "sweet_apple_acres");
p.child(UItems.ZAP_BULB).criterion("has_zap_apple", hasItems(UItems.ZAP_APPLE)).build(consumer, "trick_apple").children(pp -> {
pp.child(UItems.ZAP_APPLE).hidden().criterion("eat_trick_apple", CustomEventCriterion.createFlying("eat_trick_apple")).build(consumer, "eat_trick_apple");
pp.child(UItems.ZAP_APPLE).hidden().criterion("feed_trick_apple", CustomEventCriterion.createFlying("feed_trick_apple")).build(consumer, "feed_trick_apple");
});
p.child(UItems.JUICE).criterion("has_juice", hasItems(UItems.JUICE)).build(consumer, "juice")
.child(UItems.BURNED_JUICE).hidden().criterion("has_burned_juice", hasItems(UItems.BURNED_JUICE)).build(consumer, "burn_juice")
.child(UItems.CIDER).visible().criterion("has_cider", hasItems(UItems.CIDER)).rewards(AdvancementRewards.Builder.experience(12)).build(consumer, "brew_cider");
});
}
private void generatePegasusTribeAdvancementsTree(Consumer<AdvancementEntry> consumer, AdvancementDisplayBuilder.Parent parent) {
parent.child(Items.PHANTOM_MEMBRANE).hidden().frame(AdvancementFrame.CHALLENGE).criterion("deter_phantom", CustomEventCriterion.createFlying("kill_phantom_while_flying")).rewards(AdvancementRewards.Builder.experience(100)).build(consumer, "deter_phantom");
parent.child(Items.GLASS_PANE).criterion("break_window", CustomEventCriterion.createFlying("break_window")).rewards(AdvancementRewards.Builder.experience(10)).build(consumer, "rainbow_crash");
parent.child(UItems.PEGASUS_BADGE).criterion("fly_through_the_pain", CustomEventCriterion.createFlying("second_wind")).rewards(AdvancementRewards.Builder.experience(10)).build(consumer, "second_wind");
parent.child(UItems.EMPTY_JAR).criterion("has_empty_jar", hasItems(UItems.EMPTY_JAR)).build(consumer, "jar")
.child(UItems.RAIN_CLOUD_JAR).criterion("has_cloud_jar", hasItems(UTags.Items.CLOUD_JARS)).rewards(AdvancementRewards.Builder.experience(55)).build(consumer, "gotcha");
parent.child(UItems.LIGHTNING_JAR).frame(AdvancementFrame.CHALLENGE).criterion("lightning_strike", CustomEventCriterion.createFlying("lightning_strike")).rewards(AdvancementRewards.Builder.experience(30)).build(consumer, "mid_flight_interruption").children(p -> {
p.child(UItems.LIGHTNING_JAR).hidden().frame(AdvancementFrame.CHALLENGE).apply(d -> applyLightningBugCriterions(d, RacePredicate.of(Set.of(Race.CHANGELING), Set.of()), 10, 90)).build(consumer, "lightning_bug");
p.child(UItems.LIGHTNING_JAR).hidden().frame(AdvancementFrame.CHALLENGE).apply(d -> applyLightningBugCriterions(d, RacePredicate.of(Set.of(), Set.of(Race.CHANGELING)), 10, 90)).build(consumer, "wonder_bolt");
});
parent.child(UItems.PEGASUS_FEATHER).hidden().frame(AdvancementFrame.CHALLENGE).criterion("shed_feather", CustomEventCriterion.createFlying("shed_feather")).rewards(AdvancementRewards.Builder.experience(1)).build(consumer, "molting_season_1")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 2, 2)).build(consumer, "molting_season_2")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 4, 8)).build(consumer, "molting_season_3")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 8, 20)).build(consumer, "molting_season_4")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 16, 40)).build(consumer, "molting_season_5")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 32, 80)).build(consumer, "molting_season_6")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 64, 200)).build(consumer, "molting_season_7")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 128, 500)).build(consumer, "molting_season_8")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 256, 1000)).build(consumer, "molting_season_9")
.child(UItems.PEGASUS_FEATHER).apply(d -> applyShedFeatherCriterions(d, 512, 2280)).build(consumer, "molting_season_10")
.child(UItems.GOLDEN_FEATHER).apply(d -> applyShedFeatherCriterions(d, 1024, 4560)).build(consumer, "molting_season_11")
.child(UItems.GOLDEN_FEATHER).apply(d -> applyShedFeatherCriterions(d, 2048, 10000)).frame(AdvancementFrame.GOAL).build(consumer, "dedicated_flier");
}
private AdvancementDisplayBuilder applyShedFeatherCriterions(AdvancementDisplayBuilder builder, int repeats, int experience) {
for (int i = 1; i <= repeats; i++) {
builder.criterion("shed_feather_" + i, CustomEventCriterion.createFlying("shed_feather", i));
}
return builder.criteriaMerger(AdvancementRequirements.CriterionMerger.AND).rewards(AdvancementRewards.Builder.experience(experience));
}
private AdvancementDisplayBuilder applyLightningBugCriterions(AdvancementDisplayBuilder builder, RacePredicate race, int repeats, int experience) {
for (int i = 1; i <= repeats; i++) {
builder.criterion("lightning_struck_player_" + i, UCriteria.CUSTOM_EVENT.create(new CustomEventCriterion.Conditions(Optional.empty(), "lightning_struck_player", race, TriState.TRUE, i)));
}
return builder.criteriaMerger(AdvancementRequirements.CriterionMerger.AND).rewards(AdvancementRewards.Builder.experience(experience));
}
private void generateUnicornTribeAdvancementsTree(Consumer<AdvancementEntry> consumer, AdvancementDisplayBuilder.Parent parent) {
parent.child(UItems.SPELLBOOK).criterion("has_spellbook", hasItems(UItems.SPELLBOOK)).build(consumer, "books").children(p -> {
// TODO:
//ItemPredicate bookPredicate = ItemPredicate.Builder.create().tag(ItemTags.BOOKSHELF_BOOKS).build();
//p.child(Items.BOOK).hidden().frame(AdvancementFrame.CHALLENGE).criterion("has_books", InventoryChangedCriterion.Conditions.items(IntStream.range(0, 9 * 4).mapToObj(i -> bookPredicate).toArray(ItemPredicate[]::new))).build(consumer, "books_books_books");
p.child(UItems.CRYSTAL_SHARD).criterion("has_shard", hasItems(UItems.CRYSTAL_SHARD)).build(consumer, "crystaline").children(pp -> {
pp.child(UItems.CRYSTAL_HEART).criterion("power_up_heart", CustomEventCriterion.create("power_up_heart")).rewards(AdvancementRewards.Builder.experience(105)).build(consumer, "power_up_heart");
});
p.child(UItems.ALICORN_AMULET).criterion("has_alicorn_amulet", hasItems(UItems.ALICORN_AMULET)).build(consumer, "tempted")
.child(Items.CRYING_OBSIDIAN).criterion("light_altar", CustomEventCriterion.create("light_altar")).build(consumer, "hello_darkness_my_old_friend")
.child(UItems.BROKEN_ALICORN_AMULET).frame(AdvancementFrame.GOAL).criterion("defeat_sombra", CustomEventCriterion.create("defeat_sombra")).rewards(AdvancementRewards.Builder.experience(2000)).build(consumer, "save_the_day").children(pp -> {
pp.child(UItems.UNICORN_AMULET).frame(AdvancementFrame.GOAL).criterion("obtain_the_thing", hasItems(UItems.UNICORN_AMULET)).rewards(AdvancementRewards.Builder.experience(1100)).build(consumer, "ascension");
pp.child(UItems.BROKEN_ALICORN_AMULET).hidden().frame(AdvancementFrame.CHALLENGE).criterion("defeat_sombra_again", CustomEventCriterion.create("defeat_sombra", 2)).rewards(AdvancementRewards.Builder.experience(2000)).build(consumer, "doctor_sombrero");
});
p.child(Items.WATER_BUCKET).criterion("split_sea", CustomEventCriterion.create("split_sea")).rewards(AdvancementRewards.Builder.experience(105)).build(consumer, "split_the_sea");
});
parent.child(UItems.DRAGON_BREATH_SCROLL).showToast().announce().criterion("has_scroll", hasItems(UItems.DRAGON_BREATH_SCROLL)).build(consumer, "take_a_note").children(p -> {
p.child(UItems.DRAGON_BREATH_SCROLL).criterion("send_book", dragonScroll(false, Items.WRITTEN_BOOK)).build(consumer, "dear_princess")
.child(UItems.DRAGON_BREATH_SCROLL).criterion("send_scroll", dragonScroll(false, UItems.DRAGON_BREATH_SCROLL)).build(consumer, "i_await_your_reply");
p.child(UItems.IMPORTED_OATS).hidden().frame(AdvancementFrame.CHALLENGE)
.criterion("send_oats", dragonScroll(false, UItems.OATS, UItems.IMPORTED_OATS))
.criterion("receieve_oats", dragonScroll(true, UItems.IMPORTED_OATS))
.criteriaMerger(AdvancementRequirements.CriterionMerger.OR).build(consumer, "imported_oats");
p.child(Items.CHIPPED_ANVIL).hidden().frame(AdvancementFrame.CHALLENGE).criterion("ding_sun", dingCelestia(Set.of(), Set.of(Race.BAT))).build(consumer, "blasphemy");
p.child(Items.CHIPPED_ANVIL).hidden().frame(AdvancementFrame.CHALLENGE).criterion("ding_sun", dingCelestia(Set.of(Race.BAT), Set.of())).build(consumer, "sweet_sweet_revenge");
});
parent.child(UItems.PEGASUS_AMULET).hidden().frame(AdvancementFrame.CHALLENGE).criterion("teleport_above_world", CustomEventCriterion.create("teleport_above_world")).rewards(AdvancementRewards.Builder.experience(100)).build(consumer, "a_falling_wizard");
}
private void generateBatTribeAdvancementsTree(Consumer<AdvancementEntry> consumer, AdvancementDisplayBuilder.Parent parent) {
parent.child(Items.LIGHT).criterion("look_into_sun", CustomEventCriterion.create("look_into_sun")).build(consumer, "praise_the_sun").children(p -> {
p.child(UItems.SUNGLASSES).criterion("wear_shades", CustomEventCriterion.create("wear_shades")).build(consumer, "cool_potato");
p.child(Items.BLACK_CANDLE).frame(AdvancementFrame.CHALLENGE).criterion("screech_twenty_mobs", CustomEventCriterion.createFlying("screech_twenty_mobs")).build(consumer, "screech_twenty_mobs")
.child(Items.BRICK).frame(AdvancementFrame.CHALLENGE).criterion("super_scare_entity", CustomEventCriterion.createFlying("super_scare_entity")).build(consumer, "extra_spooky");
p.child(Items.BLACK_CANDLE).frame(AdvancementFrame.CHALLENGE).criterion("screech_self", CustomEventCriterion.createFlying("screech_self")).build(consumer, "screech_self");
});
}
private void generateHippogrifTribeAdvancementsTree(Consumer<AdvancementEntry> consumer, AdvancementDisplayBuilder.Parent parent) {
parent.child(UItems.BAITED_FISHING_ROD).showToast().announce().criterion("has_baited_fishing_rod", hasItems(UItems.BAITED_FISHING_ROD)).build(consumer, "bait");
parent.child(UItems.PEARL_NECKLACE).showToast().announce().criterion("seapony_transition", UCriteria.CUSTOM_EVENT.create(new CustomEventCriterion.Conditions(Optional.empty(), "seapony_transition", RacePredicate.of(Set.of(Race.SEAPONY), Set.of()), TriState.DEFAULT, 1))).build(consumer, "shoo_be_doo")
.child(UItems.PEARL_NECKLACE).showToast().announce().criterion("seapony_transition", UCriteria.CUSTOM_EVENT.create(new CustomEventCriterion.Conditions(Optional.empty(), "seapony_transition", RacePredicate.of(Set.of(), Set.of(Race.SEAPONY)), TriState.DEFAULT, 1))).build(consumer, "shoo_be_done");
}
private void generateEnchantmentsAdvancementsTree(Consumer<AdvancementEntry> consumer) {
AdvancementDisplayBuilder.create(Items.NETHERITE_SCRAP).showToast().announce()
.criterion("enchant_with_consumption", enchant(UEnchantments.CONSUMPTION))
.rewards(AdvancementRewards.Builder.experience(120))
.parent(new Identifier("story/enchant_item"))
.group("enchanting")
.build(consumer, "experimental")
.child(Items.NETHERITE_PICKAXE)
.criterion("use_consumption", CustomEventCriterion.create("use_consumption"))
.rewards(AdvancementRewards.Builder.experience(1200))
.group("enchanting")
.hidden()
.build(consumer, "xp_miner");
AdvancementDisplayBuilder.create(Items.GOLDEN_APPLE).showToast().announce()
.criterion("enchant_with_heart_bound", enchant(UEnchantments.HEART_BOUND))
.rewards(AdvancementRewards.Builder.experience(120))
.parent(new Identifier("story/enchant_item"))
.group("enchanting")
.build(consumer, "hearts_stronger_than_horses")
.child(Items.GOLDEN_PICKAXE)
.criterion("use_soulmate", CustomEventCriterion.create("use_soulmate"))
.rewards(AdvancementRewards.Builder.experience(1200))
.group("enchanting")
.hidden()
.build(consumer, "soulmate");
}
public static AdvancementCriterion<?> enchant(Enchantment enchantment) {
return Criteria.ENCHANTED_ITEM.create(new EnchantedItemCriterion.Conditions(
Optional.empty(),
Optional.of(ItemPredicate.Builder.create()
.enchantment(new EnchantmentPredicate(enchantment, NumberRange.IntRange.ANY))
.build()),
NumberRange.IntRange.ANY
));
}
public static AdvancementCriterion<?> dragonScroll(boolean receiving, ItemConvertible...items) {
return dragonScroll(receiving, ItemPredicate.Builder.create().items(items).build());
}
public static AdvancementCriterion<?> dragonScroll(boolean receiving, ItemPredicate items) {
return UCriteria.SEND_DRAGON_BREATH.create(new SendViaDragonBreathScrollCriterion.Conditions(
Optional.empty(),
Optional.of(items),
receiving,
Optional.empty(),
TriState.DEFAULT,
Optional.empty(),
RacePredicate.EMPTY
));
}
static AdvancementCriterion<?> hasItems(ItemConvertible...items) {
return InventoryChangedCriterion.Conditions.items(items);
}
static AdvancementCriterion<?> hasItems(TagKey<Item> items) {
return InventoryChangedCriterion.Conditions.items(ItemPredicate.Builder.create().tag(items).build());
}
static AdvancementCriterion<?> killWithItems(TagKey<DamageType> tag) {
return OnKilledCriterion.Conditions.createPlayerKilledEntity(
Optional.empty(),
Optional.of(DamageSourcePredicate.Builder.create().tag(TagPredicate.expected(tag)).build())
);
}
static AdvancementCriterion<?> dingCelestia(Set<Race> includeTribes, Set<Race> excludeTribes) {
return UCriteria.SEND_DRAGON_BREATH.create(new SendViaDragonBreathScrollCriterion.Conditions(
Optional.empty(),
Optional.of(ItemPredicate.Builder.create().tag(UTags.Items.IS_DELIVERED_AGGRESSIVELY).build()),
false,
Optional.of("princess celestia"),
TriState.FALSE,
Optional.of("dings_on_celestias_head"),
RacePredicate.of(includeTribes, excludeTribes)));
}
}

View file

@ -16,6 +16,7 @@ import com.minelittlepony.unicopia.block.ShellsBlock;
import com.minelittlepony.unicopia.block.SlimePustuleBlock;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.block.zap.ZapAppleLeavesBlock;
import com.minelittlepony.unicopia.datagen.Datagen;
import com.minelittlepony.unicopia.datagen.UBlockFamilies;
import com.minelittlepony.unicopia.server.world.Tree;
@ -35,12 +36,12 @@ import net.minecraft.data.client.Models;
import net.minecraft.data.client.MultipartBlockStateSupplier;
import net.minecraft.data.client.TextureMap;
import net.minecraft.data.client.TexturedModel;
import net.minecraft.data.client.VariantSettings;
import net.minecraft.data.client.VariantsBlockStateSupplier;
import net.minecraft.data.client.When;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.EnumProperty;
import net.minecraft.state.property.Properties;
@ -108,11 +109,11 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
// chitin blocks
registerTopsoil(UBlocks.SURFACE_CHITIN, UBlocks.CHITIN);
registerHollow(UBlocks.CHITIN);
registerCubeAllModelTexturePool(UBlocks.CHISELLED_CHITIN).stairs(UBlocks.CHISELLED_CHITIN_STAIRS).slab(UBlocks.CHISELLED_CHITIN_SLAB);
registerCubeAllModelTexturePool(UBlocks.CHISELLED_CHITIN).family(UBlockFamilies.CHISELED_CHITIN);
registerHiveBlock(UBlocks.HIVE);
registerRotated(UBlocks.CHITIN_SPIKES, BlockModels.SPIKES);
registerHull(UBlocks.CHISELLED_CHITIN_HULL, UBlocks.CHITIN, UBlocks.CHISELLED_CHITIN);
registerParentedItemModel(UBlocks.SLIME_PUSTULE, ModelIds.getBlockSubModelId(UBlocks.SLIME_PUSTULE, "_pod"));
registerItemModel(UBlocks.SLIME_PUSTULE.asItem());
blockStateCollector.accept(VariantsBlockStateSupplier.create(UBlocks.SLIME_PUSTULE)
.coordinate(BlockStateVariantMap.create(SlimePustuleBlock.SHAPE)
.register(state -> BlockStateVariant.create().put(MODEL, ModelIds.getBlockSubModelId(UBlocks.SLIME_PUSTULE, "_" + state.asString())))));
@ -123,7 +124,7 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
registerLog(UBlocks.STRIPPED_PALM_LOG).log(UBlocks.STRIPPED_PALM_LOG).wood(UBlocks.STRIPPED_PALM_WOOD);
registerCubeAllModelTexturePool(UBlocks.PALM_PLANKS).family(UBlockFamilies.PALM);
registerHangingSign(UBlocks.STRIPPED_PALM_LOG, UBlocks.PALM_HANGING_SIGN, UBlocks.PALM_WALL_HANGING_SIGN);
registerSimpleCubeAll(UBlocks.PALM_LEAVES);
registerSingleton(UBlocks.PALM_LEAVES, TexturedModel.LEAVES);
// zap wood
registerLog(UBlocks.ZAP_LOG)
@ -170,12 +171,25 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
// shells
registerAll(UBlockStateModelGenerator::registerShell, UBlocks.CLAM_SHELL, UBlocks.TURRET_SHELL, UBlocks.SCALLOP_SHELL);
// other
registerSimpleCubeAll(UBlocks.WORM_BLOCK);
registerBuiltinWithParticle(UBlocks.WEATHER_VANE, UBlocks.WEATHER_VANE.asItem());
registerWithStages(UBlocks.FROSTED_OBSIDIAN, Properties.AGE_3, BlockModels.CUBE_ALL, 0, 1, 2, 3);
registerWithStagesBuiltinModels(UBlocks.ROCKS, Properties.AGE_7, 0, 1, 2, 3, 4, 5, 6, 7);
registerWithStagesBuiltinModels(UBlocks.MYSTERIOUS_EGG, PileBlock.COUNT, 1, 2, 3);
excludeFromSimpleItemModelGeneration(UBlocks.MYSTERIOUS_EGG);
registerItemModel(UBlocks.MYSTERIOUS_EGG.asItem());
FireModels.registerSoulFire(this, UBlocks.SPECTRAL_FIRE, Blocks.SOUL_FIRE);
blockStateCollector.accept(createSingletonBlockState(UBlocks.JAR, BlockModels.TEMPLATE_JAR));
registerWeatherJar(UBlocks.CLOUD_JAR);
registerWeatherJar(UBlocks.STORM_JAR);
registerWeatherJar(UBlocks.ZAP_JAR);
registerWeatherJar(UBlocks.LIGHTNING_JAR);
}
public void registerWeatherJar(Block jar) {
blockStateCollector.accept(MultipartBlockStateSupplier.create(jar)
.with(BlockStateVariant.create().put(VariantSettings.MODEL, BlockModels.TEMPLATE_JAR))
.with(BlockStateVariant.create().put(VariantSettings.MODEL, ModelIds.getBlockSubModelId(jar, "_filling"))));
}
@SafeVarargs
@ -381,9 +395,17 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
Identifier middle = BlockModels.TEMPLATE_PILLAR.upload(pillar, textures, modelCollector);
Identifier end = BlockModels.TEMPLATE_PILLAR_END.upload(pillar, textures, modelCollector);
blockStateCollector.accept(MultipartBlockStateSupplier.create(pillar)
.with(BlockStateVariant.create().put(MODEL, middle))
.with(When.create().set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(UVLOCK, true).put(X, R180))
.with(When.create().set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end))
.with(When.create().set(Properties.AXIS, Direction.Axis.X), BlockStateVariant.create().put(MODEL, middle).put(X, R90).put(Y, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.X).set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R270).put(Y, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.X).set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R90).put(Y, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.Y), BlockStateVariant.create().put(MODEL, middle))
.with(When.create().set(Properties.AXIS, Direction.Axis.Y).set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R180))
.with(When.create().set(Properties.AXIS, Direction.Axis.Y).set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end))
.with(When.create().set(Properties.AXIS, Direction.Axis.Z), BlockStateVariant.create().put(MODEL, middle).put(X, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.Z).set(Properties.NORTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R90))
.with(When.create().set(Properties.AXIS, Direction.Axis.Z).set(Properties.SOUTH, false), BlockStateVariant.create().put(MODEL, end).put(X, R270))
);
ItemModels.TEMPLATE_PILLAR.upload(ModelIds.getItemModelId(pillar.asItem()), textures, modelCollector);
}
@ -407,9 +429,7 @@ public class UBlockStateModelGenerator extends BlockStateModelGenerator {
Identifier side = baseBlockId.withPath(p -> "block/" + p + "_side");
TextureMap textures = new TextureMap().put(TOP, top).put(SIDE, side);
MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(Registries.BLOCK.getOrEmpty(blockId).orElseGet(() -> {
return Registry.register(Registries.BLOCK, blockId, new EdibleBlock(blockId, blockId, false));
}));
MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(Datagen.getOrCreateBaleBlock(blockId));
Map<Integer, Identifier> uploadedModels = new HashMap<>();
for (Direction.Axis axis : Direction.Axis.VALUES) {

View file

@ -1,189 +0,0 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UConventionalTags;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.Datagen;
import com.minelittlepony.unicopia.datagen.ItemFamilies;
import com.minelittlepony.unicopia.item.BedsheetsItem;
import com.minelittlepony.unicopia.item.UItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalItemTags;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.registry.tag.TagBuilder;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public class UItemTagProvider extends FabricTagProvider.ItemTagProvider {
private final UBlockTagProvider blockTagProvider;
public UItemTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture, UBlockTagProvider blockTagProvider) {
super(output, registriesFuture, blockTagProvider);
this.blockTagProvider = blockTagProvider;
}
@Override
public void copy(TagKey<Block> blockTag, TagKey<Item> itemTag) {
TagBuilder blockTagBuilder = Objects.requireNonNull(blockTagProvider, "Pass Block tag provider via constructor to use copy").getTagBuilder(blockTag);
TagBuilder itemTagBuilder = getTagBuilder(itemTag);
blockTagBuilder.build().forEach(entry -> {
if (entry.canAdd(Registries.ITEM::containsId, tagId -> getTagBuilder(TagKey.of(RegistryKeys.ITEM, tagId)) != null)) {
itemTagBuilder.add(entry);
} else {
Datagen.LOGGER.warn("Cannot copy missing entry {} to item tag {}", entry, itemTag.id());
}
});
}
@Override
protected void configure(WrapperLookup arg) {
copyBlockTags();
exportConventionalTags();
getOrCreateTagBuilder(ItemTags.BOOKSHELF_BOOKS).add(UItems.SPELLBOOK);
getOrCreateTagBuilder(ItemTags.BEDS).add(UItems.CLOTH_BED, UItems.CLOUD_BED);
getOrCreateTagBuilder(ItemTags.CHEST_BOATS).add(UItems.PALM_CHEST_BOAT);
getOrCreateTagBuilder(ItemTags.BOATS).add(UItems.PALM_BOAT);
getOrCreateTagBuilder(ItemTags.MUSIC_DISCS).add(ItemFamilies.MUSIC_DISCS);
getOrCreateTagBuilder(ItemTags.CREEPER_DROP_MUSIC_DISCS).add(UItems.MUSIC_DISC_CRUSADE, UItems.MUSIC_DISC_FUNK, UItems.MUSIC_DISC_PET, UItems.MUSIC_DISC_POPULAR);
getOrCreateTagBuilder(ItemTags.SIGNS).add(UBlocks.PALM_SIGN.asItem());
getOrCreateTagBuilder(ItemTags.HANGING_SIGNS).add(UBlocks.PALM_HANGING_SIGN.asItem());
getOrCreateTagBuilder(UTags.HORSE_SHOES).add(ItemFamilies.HORSE_SHOES);
getOrCreateTagBuilder(UTags.POLEARMS).add(ItemFamilies.POLEARMS);
getOrCreateTagBuilder(ItemTags.TOOLS).addTag(UTags.HORSE_SHOES).addTag(UTags.POLEARMS);
getOrCreateTagBuilder(UTags.BASKETS).add(ItemFamilies.BASKETS);
getOrCreateTagBuilder(UTags.BADGES).add(Race.REGISTRY.stream()
.map(race -> race.getId().withPath(p -> p + "_badge"))
.flatMap(id -> Registries.ITEM.getOrEmpty(id).stream())
.toArray(Item[]::new));
getOrCreateTagBuilder(UTags.BED_SHEETS).add(BedsheetsItem.ITEMS.values().stream().toArray(Item[]::new));
getOrCreateTagBuilder(UTags.APPLE_SEEDS).add(UItems.GREEN_APPLE_SEEDS, UItems.SWEET_APPLE_SEEDS, UItems.SOUR_APPLE_SEEDS);
getOrCreateTagBuilder(UTags.MAGIC_FEATHERS).add(UItems.PEGASUS_FEATHER, UItems.GRYPHON_FEATHER);
getOrCreateTagBuilder(UTags.FRESH_APPLES).add(Items.APPLE, UItems.GREEN_APPLE, UItems.SWEET_APPLE, UItems.SOUR_APPLE);
getOrCreateTagBuilder(UTags.CLOUD_JARS).add(UItems.RAIN_CLOUD_JAR, UItems.STORM_CLOUD_JAR);
getOrCreateTagBuilder(UTags.PIES).add(UItems.APPLE_PIE, UItems.APPLE_PIE_HOOF);
// technical tags
getOrCreateTagBuilder(ItemTags.VILLAGER_PLANTABLE_SEEDS).addTag(UTags.APPLE_SEEDS);
getOrCreateTagBuilder(UTags.CAN_CUT_PIE).forceAddTag(ConventionalItemTags.SHEARS).addOptionalTag(UConventionalTags.TOOL_KNIVES);
getOrCreateTagBuilder(UTags.COOLS_OFF_KIRINS).add(Items.MELON_SLICE, UItems.JUICE).forceAddTag(ConventionalItemTags.WATER_BUCKETS);
getOrCreateTagBuilder(UTags.FALLS_SLOWLY).add(Items.FEATHER, UItems.CLOUD_LUMP).forceAddTag(UTags.MAGIC_FEATHERS);
getOrCreateTagBuilder(UTags.IS_DELIVERED_AGGRESSIVELY).forceAddTag(ItemTags.ANVIL);
getOrCreateTagBuilder(UTags.SPOOKED_MOB_DROPS).add(Items.BRICK);
getOrCreateTagBuilder(UTags.SHADES).add(
Items.CARVED_PUMPKIN, Items.SKELETON_SKULL, Items.WITHER_SKELETON_SKULL, Items.PLAYER_HEAD,
Items.ZOMBIE_HEAD, Items.CREEPER_HEAD, Items.DRAGON_HEAD, Items.PIGLIN_HEAD,
UItems.SUNGLASSES
);
getOrCreateTagBuilder(UTags.FLOATS_ON_CLOUDS)
.forceAddTag(UTags.Items.CLOUD_BEDS)
.forceAddTag(UTags.Items.CLOUD_SLABS)
.forceAddTag(UTags.Items.CLOUD_STAIRS)
.forceAddTag(UTags.Items.CLOUD_BLOCKS)
.add(UItems.CLOUD_LUMP);
getOrCreateTagBuilder(UTags.HAS_NO_TRAITS).add(
Items.AIR, Items.SPAWNER, Items.STRUCTURE_VOID, Items.STRUCTURE_BLOCK,
Items.COMMAND_BLOCK, Items.CHAIN_COMMAND_BLOCK, Items.REPEATING_COMMAND_BLOCK,
Items.LIGHT, Items.JIGSAW, Items.BARRIER, Items.BEDROCK, Items.END_PORTAL_FRAME,
Items.DEBUG_STICK, Items.COMMAND_BLOCK_MINECART,
UItems.PLUNDER_VINE
).forceAddTag(UTags.BADGES);
getOrCreateTagBuilder(UTags.LOOT_BUG_HIGH_VALUE_DROPS).add(
Items.DIAMOND, Items.GOLDEN_APPLE, Items.GOLDEN_CARROT,
Items.GOLDEN_HELMET, Items.GOLDEN_BOOTS, Items.GOLDEN_LEGGINGS, Items.GOLDEN_CHESTPLATE,
Items.GOLDEN_HORSE_ARMOR,
Items.GOLDEN_PICKAXE, Items.GOLDEN_SHOVEL, Items.GOLDEN_AXE, Items.GOLDEN_SWORD, Items.GOLDEN_HOE,
UItems.GOLDEN_HORSE_SHOE, UItems.GOLDEN_POLEARM, UItems.GOLDEN_FEATHER, UItems.GOLDEN_WING,
UItems.GOLDEN_OAK_SEEDS
).forceAddTag(ConventionalItemTags.NUGGETS)
.forceAddTag(ConventionalItemTags.GOLD_INGOTS).forceAddTag(ConventionalItemTags.RAW_GOLD_ORES).forceAddTag(ConventionalItemTags.RAW_GOLD_BLOCKS)
.addOptionalTag(new Identifier("farmersdelight:golden_knife"));
exportFarmersDelightItems();
}
private void copyBlockTags() {
copy(BlockTags.LEAVES, ItemTags.LEAVES);
copy(BlockTags.LOGS_THAT_BURN, ItemTags.LOGS_THAT_BURN);
copy(BlockTags.LOGS, ItemTags.LOGS);
copy(BlockTags.PLANKS, ItemTags.PLANKS);
copy(BlockTags.WOODEN_BUTTONS, ItemTags.WOODEN_BUTTONS);
copy(BlockTags.WOODEN_DOORS, ItemTags.WOODEN_DOORS);
copy(BlockTags.FENCE_GATES, ItemTags.FENCE_GATES);
copy(BlockTags.WOODEN_FENCES, ItemTags.WOODEN_FENCES);
copy(BlockTags.WOODEN_PRESSURE_PLATES, ItemTags.WOODEN_PRESSURE_PLATES);
copy(BlockTags.SLABS, ItemTags.SLABS);
copy(BlockTags.WOODEN_SLABS, ItemTags.WOODEN_SLABS);
copy(BlockTags.STAIRS, ItemTags.STAIRS);
copy(BlockTags.WOODEN_STAIRS, ItemTags.WOODEN_STAIRS);
copy(BlockTags.TRAPDOORS, ItemTags.TRAPDOORS);
copy(BlockTags.WOODEN_TRAPDOORS, ItemTags.WOODEN_TRAPDOORS);
copy(BlockTags.SAPLINGS, ItemTags.SAPLINGS);
copy(UTags.Blocks.ZAP_LOGS, UTags.Items.ZAP_LOGS);
copy(UTags.Blocks.WAXED_ZAP_LOGS, UTags.Items.WAXED_ZAP_LOGS);
copy(UTags.Blocks.PALM_LOGS, UTags.Items.PALM_LOGS);
copy(UTags.Blocks.CLOUD_BEDS, UTags.Items.CLOUD_BEDS);
copy(UTags.Blocks.CLOUD_SLABS, UTags.Items.CLOUD_SLABS);
copy(UTags.Blocks.CLOUD_STAIRS, UTags.Items.CLOUD_STAIRS);
copy(UTags.Blocks.CLOUD_BLOCKS, UTags.Items.CLOUD_BLOCKS);
copy(UTags.Blocks.CHITIN_BLOCKS, UTags.Items.CHITIN_BLOCKS);
}
private void exportConventionalTags() {
getOrCreateTagBuilder(UConventionalTags.ACORNS).add(UItems.ACORN);
getOrCreateTagBuilder(UConventionalTags.APPLES)
.add(Items.APPLE, Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE, UItems.ROTTEN_APPLE)
.forceAddTag(UTags.FRESH_APPLES)
.addOptionalTag(new Identifier("c", "pyrite_apples")) // no idea which mod add pyrite apples
;
getOrCreateTagBuilder(UConventionalTags.BANANAS).add(UItems.BANANA);
getOrCreateTagBuilder(UConventionalTags.COOKED_FISH).add(Items.COOKED_COD, Items.COOKED_SALMON);
getOrCreateTagBuilder(UConventionalTags.STICKS).add(Items.STICK);
getOrCreateTagBuilder(UConventionalTags.PINECONES).add(UItems.PINECONE);
getOrCreateTagBuilder(UConventionalTags.PINEAPPLES).add(UItems.PINEAPPLE);
getOrCreateTagBuilder(UConventionalTags.MANGOES).add(UItems.MANGO);
getOrCreateTagBuilder(UConventionalTags.MUSHROOMS).add(Items.RED_MUSHROOM, Items.BROWN_MUSHROOM);
getOrCreateTagBuilder(UConventionalTags.MUFFINS).add(UItems.MUFFIN);
getOrCreateTagBuilder(UConventionalTags.SEEDS).add(Items.BEETROOT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.TORCHFLOWER_SEEDS, Items.WHEAT_SEEDS)
.add(UItems.OAT_SEEDS)
.forceAddTag(UTags.APPLE_SEEDS);
getOrCreateTagBuilder(UConventionalTags.OEATMEALS).add(UItems.OATMEAL);
getOrCreateTagBuilder(UConventionalTags.GRAIN).add(Items.WHEAT, UItems.OATS);
getOrCreateTagBuilder(UConventionalTags.NUTS).addOptionalTag(UConventionalTags.CROPS_PEANUTS);
getOrCreateTagBuilder(UConventionalTags.FRUITS)
.forceAddTag(UConventionalTags.MANGOES)
.forceAddTag(UConventionalTags.PINEAPPLES)
.forceAddTag(UConventionalTags.APPLES)
.forceAddTag(UConventionalTags.BANANAS);
}
private void exportFarmersDelightItems() {
getOrCreateTagBuilder(UTags.COOLS_OFF_KIRINS)
.addOptional(new Identifier("farmersdelight:melon_popsicle"))
.addOptional(new Identifier("farmersdelight:melon_juice"));
getOrCreateTagBuilder(TagKey.of(RegistryKeys.ITEM, new Identifier("farmersdelight:cabbage_roll_ingredients"))).add(UItems.OATS, UItems.ROCK, UItems.WHEAT_WORMS);
getOrCreateTagBuilder(TagKey.of(RegistryKeys.ITEM, new Identifier("farmersdelight:comfort_foods"))).add(UItems.OATMEAL, UItems.ROCK_STEW, UItems.MUFFIN);
}
}

View file

@ -19,6 +19,7 @@ import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.data.client.ItemModelGenerator;
import net.minecraft.data.client.ModelIds;
import net.minecraft.data.client.Models;
import net.minecraft.data.client.TextureKey;
import net.minecraft.data.client.TextureMap;
@ -57,21 +58,24 @@ public class UModelProvider extends FabricModelProvider {
public void generateItemModels(ItemModelGenerator itemModelGenerator) {
ItemModels.register(itemModelGenerator,
UItems.ACORN, UItems.APPLE_PIE_HOOF, UItems.APPLE_PIE_SLICE, UItems.APPLE_PIE,
UItems.BANANA, UItems.BOTCHED_GEM, UItems.BROKEN_SUNGLASSES, UItems.BURNED_JUICE, UItems.BURNED_TOAST,
UItems.CARAPACE, UItems.CLAM_SHELL, UItems.COOKED_ZAP_APPLE, UItems.CLOUD_LUMP, UItems.CRISPY_HAY_FRIES, UItems.CRYSTAL_HEART, UItems.CRYSTAL_SHARD,
UItems.BANANA, UItems.BOTCHED_GEM, UItems.BOWL_OF_NUTS, UItems.BROKEN_SUNGLASSES, UItems.BURNED_JUICE, UItems.BURNED_TOAST,
UItems.CARAPACE, UItems.CLAM_SHELL, UItems.COOKED_ZAP_APPLE, UItems.CHOCOLATE_OATMEAL_COOKIE,
UItems.CLOUD_LUMP, UItems.CRISPY_HAY_FRIES, UItems.CRYSTAL_HEART, UItems.CRYSTAL_SHARD,
UItems.COOKED_TROPICAL_FISH, UItems.COOKED_PUFFERFISH, UItems.FRIED_AXOLOTL,
UItems.DAFFODIL_DAISY_SANDWICH, UItems.DRAGON_BREATH_SCROLL,
UItems.EMPTY_JAR,
UItems.FRIENDSHIP_BRACELET,
UItems.GIANT_BALLOON, UItems.GOLDEN_FEATHER, UItems.GOLDEN_OAK_SEEDS, UItems.GOLDEN_WING, UItems.GREEN_APPLE_SEEDS, UItems.GREEN_APPLE, UItems.GROGARS_BELL,
UItems.GRYPHON_FEATHER,
UItems.GRYPHON_FEATHER, UItems.GREEN_FRIED_EGG,
UItems.HAY_BURGER, UItems.HAY_FRIES, UItems.HORSE_SHOE_FRIES,
UItems.IMPORTED_OATS,
UItems.JAM_TOAST, UItems.JUICE,
UItems.LIGHTNING_JAR,
UItems.MANGO, UItems.MUFFIN,
UItems.OATMEAL,
UItems.PEBBLES, UItems.PEGASUS_FEATHER, UItems.PINECONE, UItems.PINEAPPLE_CROWN,
UItems.RAIN_CLOUD_JAR, UItems.ROCK_STEW, UItems.ROCK, UItems.ROTTEN_APPLE,
UItems.OATMEAL, UItems.OATMEAL_COOKIE, UItems.SCONE,
UItems.PEBBLES, UItems.PEGASUS_FEATHER, UItems.PINECONE, UItems.PINECONE_COOKIE, UItems.PINEAPPLE_CROWN,
UItems.RAIN_CLOUD_JAR, UItems.ROCK_STEW, UItems.ROCK,
UItems.ROTTEN_APPLE, UItems.ROTTEN_COD, UItems.ROTTEN_TROPICAL_FISH, UItems.ROTTEN_SALMON, UItems.ROTTEN_PUFFERFISH,
UItems.SALT_CUBE, UItems.SCALLOP_SHELL, UItems.SHELLY, UItems.SOUR_APPLE_SEEDS, UItems.SOUR_APPLE, UItems.SPELLBOOK, UItems.STORM_CLOUD_JAR,
UItems.SWEET_APPLE_SEEDS, UItems.SWEET_APPLE,
UItems.TOAST, UItems.TOM, UItems.TURRET_SHELL,
@ -105,7 +109,10 @@ public class UModelProvider extends FabricModelProvider {
.put(TextureKey.LAYER1, ModelIds.getItemSubModelId(UItems.MAGIC_STAFF, "_magic")), itemModelGenerator.writer);
// polearms
List.of(UItems.DIAMOND_POLEARM, UItems.GOLDEN_POLEARM, UItems.NETHERITE_POLEARM, UItems.STONE_POLEARM, UItems.WOODEN_POLEARM, UItems.IRON_POLEARM).forEach(item -> ItemModels.registerPolearm(itemModelGenerator, item));
List.of(
UItems.DIAMOND_POLEARM, UItems.GOLDEN_POLEARM, UItems.NETHERITE_POLEARM,
UItems.STONE_POLEARM, UItems.WOODEN_POLEARM, UItems.IRON_POLEARM
).forEach(item -> ItemModels.registerPolearm(itemModelGenerator, item));
// sheets
ItemModels.register(itemModelGenerator, BedsheetsItem.ITEMS.values().stream().toArray(Item[]::new));
// badges
@ -133,5 +140,8 @@ public class UModelProvider extends FabricModelProvider {
.addOverride(ModelIds.getItemSubModelId(UItems.GEMSTONE, "_pure"), "affinity", 0)
.addOverride(ModelIds.getItemSubModelId(UItems.GEMSTONE, "_corrupted"), "affinity", 1)
.upload(UItems.GEMSTONE, itemModelGenerator);
// fishing rod
ItemModels.register(itemModelGenerator, Models.HANDHELD_ROD, UItems.BAITED_FISHING_ROD);
}
}

View file

@ -1,88 +0,0 @@
package com.minelittlepony.unicopia.datagen.providers;
import java.util.Arrays;
import java.util.NoSuchElementException;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.datagen.ItemFamilies;
import com.minelittlepony.unicopia.datagen.UBlockFamilies;
import com.minelittlepony.unicopia.item.UItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.block.Block;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.RecipeProvider;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
import net.minecraft.data.server.recipe.VanillaRecipeProvider;
import net.minecraft.item.Item;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.Items;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.registry.Registries;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.util.Identifier;
public class URecipeProvider extends FabricRecipeProvider {
public URecipeProvider(FabricDataOutput output) {
super(output);
}
@Override
public void generate(RecipeExporter exporter) {
Arrays.stream(ItemFamilies.BASKETS).forEach(basket -> {
offerBasketRecipe(exporter, basket, getMaterial(basket, "_basket", "_planks"));
});
offerBoatRecipe(exporter, UItems.PALM_BOAT, UBlocks.PALM_PLANKS);
offerChestBoatRecipe(exporter, UItems.PALM_CHEST_BOAT, UItems.PALM_BOAT);
offerHangingSignRecipe(exporter, UBlocks.PALM_HANGING_SIGN, UBlocks.PALM_PLANKS);
offerPlanksRecipe(exporter, UBlocks.PALM_PLANKS, UTags.Items.PALM_LOGS, 4);
offerPlanksRecipe(exporter, UBlocks.ZAP_PLANKS, UTags.Items.ZAP_LOGS, 4);
offerPlanksRecipe(exporter, UBlocks.WAXED_ZAP_PLANKS, UTags.Items.WAXED_ZAP_LOGS, 4);
offerBarkBlockRecipe(exporter, UBlocks.PALM_WOOD, UBlocks.PALM_LOG);
offerBarkBlockRecipe(exporter, UBlocks.ZAP_WOOD, UBlocks.ZAP_LOG);
offerBarkBlockRecipe(exporter, UBlocks.WAXED_ZAP_WOOD, UBlocks.WAXED_ZAP_LOG);
generateFamily(exporter, UBlockFamilies.PALM, FeatureSet.empty());
generateFamily(exporter, UBlockFamilies.ZAP, FeatureSet.empty());
generateFamily(exporter, UBlockFamilies.WAXED_ZAP, FeatureSet.empty());
offerWaxingRecipes(exporter);
}
private static Item getMaterial(Item output, String toStrip, String suffex) {
Identifier id = Registries.ITEM.getId(output).withPath(p -> p.replace(toStrip, "") + suffex);
return Registries.ITEM.getOrEmpty(id)
.or(() -> Registries.ITEM.getOrEmpty(new Identifier(Identifier.DEFAULT_NAMESPACE, id.getPath())))
.orElseThrow(() -> new NoSuchElementException("No item with id " + id));
}
public static void offerBasketRecipe(RecipeExporter exporter, ItemConvertible output, ItemConvertible input) {
ShapedRecipeJsonBuilder.create(RecipeCategory.TRANSPORTATION, output)
.input(Character.valueOf('#'), input)
.pattern("# #")
.pattern("# #")
.pattern("###")
.group("basket")
.criterion(VanillaRecipeProvider.hasItem(input), VanillaRecipeProvider.conditionsFromItem(input))
.offerTo(exporter);
}
public static void offerWaxingRecipes(RecipeExporter exporter) {
UBlockFamilies.WAXED_ZAP.getVariants().forEach((variant, output) -> {
Block input = UBlockFamilies.ZAP.getVariant(variant);
offerWaxingRecipe(exporter, output, input);
});
offerWaxingRecipe(exporter, UBlocks.WAXED_ZAP_PLANKS, UBlocks.ZAP_PLANKS);
offerWaxingRecipe(exporter, UBlocks.WAXED_ZAP_WOOD, UBlocks.ZAP_WOOD);
}
public static void offerWaxingRecipe(RecipeExporter exporter, ItemConvertible output, ItemConvertible input) {
ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, output)
.input(input)
.input(Items.HONEYCOMB).group(RecipeProvider.getItemPath(output))
.criterion(RecipeProvider.hasItem(input), RecipeProvider.conditionsFromItem(input))
.offerTo(exporter, RecipeProvider.convertBetween(output, Items.HONEYCOMB));
}
}

Some files were not shown because too many files have changed in this diff Show more