Skip to content

Commit c77711d

Browse files
authored
Add support for sheep, cows, pigs, chickens, mooshrooms, and squids. (#1735)
* Adds Sheep * Adds Cows * Adds Double Sided box faces to BoxBuilder * Adds Chickens * Fixes missed load entities checkboxes * Adds pigs * figure out baby entity scaling * Add Mooshroom entities * add Squids * fix saving sheep material * add squid to entities tab combobox * fix sign error in Squid model * Update cows to add the cold and warm variants * add cold and warm chicken variants * add pig's new variants * Update Mooshroom texture size and model * Fix sheep wool layer and add colored sheared overlay * Recognize pre-1.11 IDs
1 parent 81b2df6 commit c77711d

File tree

21 files changed

+2447
-48
lines changed

21 files changed

+2447
-48
lines changed
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
package se.llbit.chunky.entity;
2+
3+
import se.llbit.chunky.model.builder.BoxModelBuilder;
4+
import se.llbit.chunky.model.builder.UVMapHelper;
5+
import se.llbit.chunky.resources.Texture;
6+
import se.llbit.chunky.world.material.TextureMaterial;
7+
import se.llbit.json.JsonObject;
8+
import se.llbit.json.JsonValue;
9+
import se.llbit.math.Quad;
10+
import se.llbit.math.QuickMath;
11+
import se.llbit.math.Ray;
12+
import se.llbit.math.Transform;
13+
import se.llbit.math.Vector3;
14+
import se.llbit.math.Vector4;
15+
import se.llbit.math.primitive.Primitive;
16+
import se.llbit.nbt.CompoundTag;
17+
import se.llbit.nbt.Tag;
18+
import se.llbit.util.JsonUtil;
19+
20+
import java.util.ArrayList;
21+
import java.util.Collection;
22+
23+
public class ChickenEntity extends Entity implements Poseable, Variant {
24+
25+
private static final Quad[] body = new BoxModelBuilder()
26+
.addBox(new Vector3(-3 / 16.0, -4 / 16.0, -3 / 16.0), new Vector3(3 / 16.0, 4 / 16.0, 3 / 16.0), box ->
27+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(0, 9).flipX()
28+
.addTopFace().addBottomFace(UVMapHelper.Side::flipY).addLeftFace().addRightFace().addFrontFace().addBackFace()
29+
.transform(Transform.NONE
30+
.translate(0.5, 0.5, 0.5)
31+
.rotateX(Math.toRadians(-90))
32+
.translate(-0.5, -0.5, -0.5)
33+
)
34+
).toQuads();
35+
36+
//TODO: Skip adding blank faces on Chicken legs? Same for Pig's saddle.
37+
private static final Quad[] leg = new BoxModelBuilder()
38+
.addBox(new Vector3(0 / 16.0, -5 / 16.0, 0 / 16.0), new Vector3(3 / 16.0, 0, 3 / 16.0), box ->
39+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(26, 0).flipX().doubleSided()
40+
.addTopFace().addBottomFace(UVMapHelper.Side::flipY).addLeftFace().addRightFace().addFrontFace().addBackFace()
41+
.transform(Transform.NONE.translate(0, Ray.OFFSET, 0)) // Prevent Z-Fighting with the block the Chicken is standing on
42+
).toQuads();
43+
44+
private static final Quad[] wing = new BoxModelBuilder()
45+
.addBox(new Vector3(0 / 16.0, -4 / 16.0, -3 / 16.0), new Vector3(1 / 16.0, 0 / 16.0, 3 / 16.0), box ->
46+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(24, 13).flipX()
47+
.addTopFace().addBottomFace().addLeftFace().addRightFace().addFrontFace().addBackFace()
48+
).toQuads();
49+
50+
private static final Quad[] head = new BoxModelBuilder()
51+
.addBox(new Vector3(-2 / 16.0, 0 / 16.0, -3 / 16.0), new Vector3(2 / 16.0, 6 / 16.0, 0 / 16.0), box ->
52+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(0, 0).flipX()
53+
.addTopFace().addBottomFace(UVMapHelper.Side::flipY).addLeftFace().addRightFace().addFrontFace().addBackFace()
54+
).addBox(new Vector3(-2 / 16.0, 2 / 16.0, -5 / 16.0), new Vector3(2 / 16.0, 4 / 16.0, -3 / 16.0), box ->
55+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(14, 0).flipX()
56+
.addTopFace().addBottomFace().addLeftFace().addRightFace().addFrontFace().addBackFace()
57+
).addBox(new Vector3(-1 / 16.0, 0 / 16.0, -4 / 16.0), new Vector3(1 / 16.0, 2 / 16.0, -2 / 16.0), box ->
58+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(14, 4).flipX()
59+
.addTopFace().addBottomFace().addLeftFace().addRightFace().addFrontFace().addBackFace()
60+
).toQuads();
61+
62+
private static final Quad[] cold_head = new BoxModelBuilder()
63+
.addBox(new Vector3(-2 / 16.0, 0 / 16.0, -3 / 16.0), new Vector3(2 / 16.0, 6 / 16.0, 0 / 16.0), box ->
64+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(0, 0).flipX()
65+
.addTopFace().addBottomFace(UVMapHelper.Side::flipY).addLeftFace().addRightFace().addFrontFace().addBackFace()
66+
).addBox(new Vector3(-2 / 16.0, 2 / 16.0, -5 / 16.0), new Vector3(2 / 16.0, 4 / 16.0, -3 / 16.0), box ->
67+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(14, 0).flipX()
68+
.addTopFace().addBottomFace().addLeftFace().addRightFace().addFrontFace().addBackFace()
69+
).addBox(new Vector3(-1 / 16.0, 0 / 16.0, -4 / 16.0), new Vector3(1 / 16.0, 2 / 16.0, -2 / 16.0), box ->
70+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(14, 4).flipX()
71+
.addTopFace().addBottomFace().addLeftFace().addRightFace().addFrontFace().addBackFace()
72+
).addBox(new Vector3(-3 / 16.0, 4 / 16.0, -3 / 16.0), new Vector3(3 / 16.0, 7 / 16.0, 1 / 16.0), box ->
73+
box.forTextureSize(Texture.chicken, 64, 32).atUVCoordinates(44, 0).flipX()
74+
.addTopFace().addBottomFace().addLeftFace().addRightFace().addFrontFace().addBackFace()
75+
.transform(Transform.NONE.translate(0, 0, -Ray.OFFSET)).doubleSided()
76+
).toQuads();
77+
78+
private static final Quad[] cold_tail = {
79+
new Quad(new Vector3(0, 3 / 16.0, 3 / 16.0), new Vector3(0, -2 / 16.0, 3 / 16.0), new Vector3(0, 3 / 16.0, 0), new Vector4(38 / 64.0, 43 / 64.0, 15 / 32.0, 18 / 32.0)),
80+
new Quad(new Vector3(0, 3 / 16.0, 0 / 16.0), new Vector3(0, -2 / 16.0, 0), new Vector3(0, 3 / 16.0, 3 / 16.0), new Vector4(48 / 64.0, 43 / 64.0, 18 / 32.0, 15 / 32.0))
81+
};
82+
83+
private final JsonObject pose;
84+
85+
private double scale = 1;
86+
private double headScale = 1;
87+
88+
private String variant = "minecraft:temperate";
89+
90+
private static final String[] partNames = {"all", "head", "body", "left_leg", "right_leg", "left_wing", "right_wing", "tail"};
91+
92+
public ChickenEntity(Vector3 position, CompoundTag tag) {
93+
super(position);
94+
95+
Tag rotation = tag.get("Rotation");
96+
double yaw = rotation.get(0).floatValue();
97+
double pitch = rotation.get(1).floatValue();
98+
99+
boolean isBaby = tag.get("Age").intValue(1) < 0;
100+
if (isBaby) {
101+
this.scale = 0.5;
102+
this.headScale = 2;
103+
}
104+
105+
pose = new JsonObject();
106+
pose.add("all", JsonUtil.vec3ToJson(new Vector3(0, QuickMath.degToRad(180 - yaw), 0)));
107+
pose.add("head", JsonUtil.vec3ToJson(new Vector3(QuickMath.degToRad(pitch), 0, 0)));
108+
109+
variant = tag.get("variant").stringValue("minecraft:temperate");
110+
}
111+
112+
public ChickenEntity(JsonObject json) {
113+
super(JsonUtil.vec3FromJsonObject(json.get("position")));
114+
this.scale = json.get("scale").asDouble(1);
115+
this.headScale = json.get("headScale").asDouble(1);
116+
this.pose = json.get("pose").object();
117+
this.variant = json.get("variant").stringValue("minecraft:temperate");
118+
}
119+
120+
@Override
121+
public Collection<Primitive> primitives(Vector3 offset) {
122+
ArrayList<Primitive> faces = new ArrayList<>();
123+
124+
TextureMaterial skinMaterial = switch (variant) {
125+
case "minecraft:cold" -> new TextureMaterial(Texture.coldChicken);
126+
case "minecraft:warm" -> new TextureMaterial(Texture.warmChicken);
127+
default -> new TextureMaterial(Texture.chicken);
128+
};
129+
130+
Vector3 allPose = JsonUtil.vec3FromJsonArray(pose.get("all"));
131+
Vector3 bodyPose = JsonUtil.vec3FromJsonArray(pose.get("body"));
132+
Vector3 leftLegPose = JsonUtil.vec3FromJsonArray(pose.get("left_leg"));
133+
Vector3 rightLegPose = JsonUtil.vec3FromJsonArray(pose.get("right_leg"));
134+
Vector3 leftWingPose = JsonUtil.vec3FromJsonArray(pose.get("left_wing"));
135+
Vector3 rightWingPose = JsonUtil.vec3FromJsonArray(pose.get("right_wing"));
136+
Vector3 headPose = JsonUtil.vec3FromJsonArray(pose.get("head"));
137+
Vector3 tailPose = JsonUtil.vec3FromJsonArray(pose.get("tail"));
138+
139+
Vector3 worldOffset = new Vector3(position.x + offset.x, position.y + offset.y, position.z + offset.z);
140+
Transform worldTransform = Transform.NONE
141+
.scale(scale)
142+
.rotateX(allPose.x)
143+
.rotateY(allPose.y)
144+
.rotateZ(allPose.z)
145+
.translate(worldOffset);
146+
147+
Transform transform = Transform.NONE
148+
.rotateX(bodyPose.x)
149+
.rotateY(bodyPose.y)
150+
.rotateZ(bodyPose.z)
151+
.translate(0, 8 / 16.0, 0 / 16.0)
152+
.chain(worldTransform);
153+
for (Quad quad : body) {
154+
quad.addTriangles(faces, skinMaterial, transform);
155+
}
156+
157+
if (variant.equals("minecraft:cold")) {
158+
transform = Transform.NONE
159+
.rotateX(tailPose.x)
160+
.rotateY(tailPose.y)
161+
.rotateZ(tailPose.z)
162+
.translate(0, 9 / 16.0, 3 / 16.0)
163+
.chain(worldTransform);
164+
for (Quad quad : cold_tail) {
165+
quad.addTriangles(faces, skinMaterial, transform);
166+
}
167+
}
168+
169+
transform = Transform.NONE
170+
.translate(-1.5 / 16.0, 0 / 16.0, -3 / 16.0) // Move rotation point to middle of back of the leg
171+
.rotateX(rightLegPose.x)
172+
.rotateY(rightLegPose.y)
173+
.rotateZ(rightLegPose.z)
174+
.translate(1.5 / 16.0, 5 / 16.0, 3 / 16.0)
175+
.chain(worldTransform);
176+
for (Quad quad : leg) {
177+
quad.addTriangles(faces, skinMaterial, transform);
178+
}
179+
180+
transform = Transform.NONE
181+
.translate(-1.5 / 16.0, 0 / 16.0, -3 / 16.0)
182+
.rotateX(leftLegPose.x)
183+
.rotateY(leftLegPose.y)
184+
.rotateZ(leftLegPose.z)
185+
.translate(-1.5 / 16.0, 5 / 16.0, 3 / 16.0)
186+
.chain(worldTransform);
187+
for (Quad quad : leg) {
188+
quad.addTriangles(faces, skinMaterial, transform);
189+
}
190+
191+
transform = Transform.NONE
192+
.rotateX(rightWingPose.x)
193+
.rotateY(rightWingPose.y)
194+
.rotateZ(rightWingPose.z)
195+
.translate(3 / 16.0, 11 / 16.0, 0 / 16.0)
196+
.chain(worldTransform);
197+
for (Quad quad : wing) {
198+
quad.addTriangles(faces, skinMaterial, transform);
199+
}
200+
201+
transform = Transform.NONE
202+
.translate(-1 / 16.0, 0, 0) // Correct the rotation point because we're copying the wing Quads for the right wing
203+
.rotateX(leftWingPose.x)
204+
.rotateY(leftWingPose.y)
205+
.rotateZ(leftWingPose.z)
206+
.translate(-3 / 16.0, 11 / 16.0, 0 / 16.0)
207+
.chain(worldTransform);
208+
for (Quad quad : wing) {
209+
quad.addTriangles(faces, skinMaterial, transform);
210+
}
211+
212+
transform = Transform.NONE
213+
.rotateX(headPose.x)
214+
.rotateY(headPose.y)
215+
.rotateZ(headPose.z)
216+
.scale(headScale)
217+
.translate(0, 9 / 16.0, -3 / 16.0)
218+
.chain(worldTransform);
219+
220+
if (variant.equals("minecraft:cold")) {
221+
for (Quad quad : cold_head) {
222+
quad.addTriangles(faces, skinMaterial, transform);
223+
}
224+
} else {
225+
for (Quad quad : head) {
226+
quad.addTriangles(faces, skinMaterial, transform);
227+
}
228+
}
229+
return faces;
230+
}
231+
232+
@Override
233+
public JsonValue toJson() {
234+
JsonObject json = new JsonObject();
235+
json.add("kind", "chicken");
236+
json.add("position", position.toJson());
237+
json.add("scale", getScale());
238+
json.add("headScale", headScale);
239+
json.add("pose", pose);
240+
json.add("variant", variant);
241+
242+
return json;
243+
}
244+
245+
public static ChickenEntity fromJson(JsonObject json) {
246+
return new ChickenEntity(json);
247+
}
248+
249+
@Override
250+
public String[] partNames() {
251+
return partNames;
252+
}
253+
254+
@Override
255+
public double getScale() {
256+
return scale;
257+
}
258+
259+
@Override
260+
public void setScale(double value) {
261+
scale = value;
262+
}
263+
264+
@Override
265+
public void setHeadScale(double value) {
266+
headScale = value;
267+
}
268+
269+
@Override
270+
public double getHeadScale() {
271+
return headScale;
272+
}
273+
274+
@Override
275+
public JsonObject getPose() {
276+
return pose;
277+
}
278+
279+
@Override
280+
public String[] variants() {
281+
return new String[]{"minecraft:temperate", "minecraft:cold", "minecraft:warm"};
282+
}
283+
284+
@Override
285+
public String getVariant() {
286+
return variant;
287+
}
288+
289+
@Override
290+
public void setVariant(String variant) {
291+
this.variant = variant;
292+
}
293+
}

0 commit comments

Comments
 (0)