mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-23 21:38:00 +01:00
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:
commit
1980cf634e
678 changed files with 8204 additions and 11920 deletions
4
.github/workflows/gradle-publish.yml
vendored
4
.github/workflows/gradle-publish.yml
vendored
|
@ -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
BIN
assets/models/body.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 220 B |
BIN
assets/models/cork.png
Normal file
BIN
assets/models/cork.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 B |
1
assets/models/hanging_sandbag.bbmodel
Normal file
1
assets/models/hanging_sandbag.bbmodel
Normal file
File diff suppressed because one or more lines are too long
33
assets/models/hanging_sandbag.java
Normal file
33
assets/models/hanging_sandbag.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Made with Blockbench 4.9.4
|
||||
// Exported for Minecraft version 1.17+ for Yarn
|
||||
// Paste this class into your mod and generate all required imports
|
||||
public class hanging_sandbag extends EntityModel<Entity> {
|
||||
private final ModelPart root;
|
||||
private final ModelPart bag;
|
||||
private final ModelPart cube_r1;
|
||||
private final ModelPart cube_r2;
|
||||
public hanging_sandbag(ModelPart root) {
|
||||
this.root = root.getChild("root");
|
||||
}
|
||||
public static TexturedModelData getTexturedModelData() {
|
||||
ModelData modelData = new ModelData();
|
||||
ModelPartData modelPartData = modelData.getRoot();
|
||||
ModelPartData root = modelPartData.addChild("root", ModelPartBuilder.create().uv(16, 19).cuboid(-0.5F, 0.0F, -0.5F, 1.0F, 9.0F, 1.0F, new Dilation(0.0F)), ModelTransform.pivot(0.0F, 24.0F, 0.0F));
|
||||
|
||||
ModelPartData bag = root.addChild("bag", ModelPartBuilder.create().uv(0, 0).cuboid(-3.0F, 1.0F, -3.0F, 6.0F, 7.0F, 6.0F, new Dilation(0.0F))
|
||||
.uv(12, 14).cuboid(-2.0F, 0.0F, -2.0F, 4.0F, 1.0F, 4.0F, new Dilation(0.0F))
|
||||
.uv(0, 13).cuboid(-2.0F, 8.0F, -2.0F, 4.0F, 1.0F, 4.0F, new Dilation(0.0F)), ModelTransform.pivot(0.0F, 9.0F, 0.0F));
|
||||
|
||||
ModelPartData cube_r1 = bag.addChild("cube_r1", ModelPartBuilder.create().uv(0, 14).cuboid(0.0F, 8.0F, -2.0F, 0.0F, 4.0F, 4.0F, new Dilation(0.0F)), ModelTransform.of(0.0F, 1.0F, 0.0F, 0.0F, -0.7854F, 0.0F));
|
||||
|
||||
ModelPartData cube_r2 = bag.addChild("cube_r2", ModelPartBuilder.create().uv(0, 14).cuboid(0.0F, 8.0F, -2.0F, 0.0F, 4.0F, 4.0F, new Dilation(0.0F)), ModelTransform.of(0.0F, 1.0F, 0.0F, 0.0F, 0.7854F, 0.0F));
|
||||
return TexturedModelData.of(modelData, 32, 32);
|
||||
}
|
||||
@Override
|
||||
public void setAngles(Entity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
|
||||
}
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumer vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha) {
|
||||
root.render(matrices, vertexConsumer, light, overlay, red, green, blue, alpha);
|
||||
}
|
||||
}
|
BIN
assets/models/hanging_sandbag.png
Normal file
BIN
assets/models/hanging_sandbag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -1,113 +0,0 @@
|
|||
{
|
||||
"textures": {
|
||||
"top": "blocks/hay_block_top",
|
||||
"particle": "blocks/hay_block_side",
|
||||
"side": "blocks/hay_block_side"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "bottom_south_east",
|
||||
"from": [8, 0, 8],
|
||||
"to": [16, 8, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
||||
"east": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
||||
"south": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
||||
"west": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
||||
"up": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
||||
"down": {"uv": [8, 0, 16, 8], "texture": "#top"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "top_south_east",
|
||||
"from": [8, 8, 8],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
||||
"east": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
||||
"south": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
||||
"up": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
||||
"down": {"uv": [8, 0, 16, 8], "texture": "#top"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bottom_north_east",
|
||||
"from": [8, 0, 0],
|
||||
"to": [16, 8, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
||||
"east": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
||||
"south": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
||||
"west": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
||||
"up": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
||||
"down": {"uv": [8, 8, 16, 16], "texture": "#top"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "top_north_east",
|
||||
"from": [8, 8, 0],
|
||||
"to": [16, 16, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
||||
"east": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
||||
"south": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
||||
"west": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
||||
"up": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
||||
"down": {"uv": [8, 8, 16, 16], "texture": "#top"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bottom_south_west",
|
||||
"from": [0, 0, 8],
|
||||
"to": [8, 8, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
||||
"east": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
||||
"south": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
||||
"west": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
||||
"up": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 8, 8], "texture": "#top"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "top_south_west",
|
||||
"from": [0, 8, 8],
|
||||
"to": [8, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
||||
"east": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
||||
"south": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
||||
"up": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 8, 8], "texture": "#top"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bottom_north_west",
|
||||
"from": [0, 0, 0],
|
||||
"to": [8, 8, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
||||
"east": {"uv": [8, 8, 16, 16], "texture": "#top"},
|
||||
"south": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
||||
"west": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
||||
"up": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
||||
"down": {"uv": [0, 8, 8, 16], "texture": "#top"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "top_north_west",
|
||||
"from": [0, 8, 0],
|
||||
"to": [8, 16, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
||||
"east": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
||||
"south": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
||||
"west": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
||||
"up": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
||||
"down": {"uv": [0, 8, 8, 16], "texture": "#top"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
1
assets/models/jar.bbmodel
Normal file
1
assets/models/jar.bbmodel
Normal 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
BIN
assets/models/jar_body.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 220 B |
1
assets/models/jar_cloud.bbmodel
Normal file
1
assets/models/jar_cloud.bbmodel
Normal file
File diff suppressed because one or more lines are too long
BIN
assets/models/jar_cork.png
Normal file
BIN
assets/models/jar_cork.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 B |
1
assets/models/jar_lightning.bbmodel
Normal file
1
assets/models/jar_lightning.bbmodel
Normal 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="}]}
|
1
assets/models/jar_storm.bbmodel
Normal file
1
assets/models/jar_storm.bbmodel
Normal file
File diff suppressed because one or more lines are too long
1
assets/models/jar_zap.bbmodel
Normal file
1
assets/models/jar_zap.bbmodel
Normal 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"}]}
|
31
build.gradle
31
build.gradle
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class PegasusCaptureStormAbility implements Ability<Hit> {
|
|||
|
||||
@Override
|
||||
public boolean canUse(Race race) {
|
||||
return race.canInteractWithClouds();
|
||||
return race.canInfluenceWeather();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
@ -28,7 +28,7 @@ public class PegasusRainboomAbility implements Ability<Hit> {
|
|||
|
||||
@Override
|
||||
public boolean canUse(Race race) {
|
||||
return race.canInteractWithClouds();
|
||||
return race.canInfluenceWeather();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() { }
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
116
src/main/java/com/minelittlepony/unicopia/block/JarBlock.java
Normal file
116
src/main/java/com/minelittlepony/unicopia/block/JarBlock.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) ->
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue