Skip to content

Commit 02a8248

Browse files
committed
Readd EntityUtils.
1 parent f2b8877 commit 02a8248

File tree

1 file changed

+287
-0
lines changed

1 file changed

+287
-0
lines changed
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
package net.darkhax.bookshelf.api.util;
2+
3+
import java.util.HashMap;
4+
import java.util.HashSet;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Set;
8+
9+
import net.minecraft.core.BlockPos;
10+
import net.minecraft.core.Direction;
11+
import net.minecraft.util.Tuple;
12+
import net.minecraft.world.effect.MobEffect;
13+
import net.minecraft.world.effect.MobEffectInstance;
14+
import net.minecraft.world.effect.MobEffects;
15+
import net.minecraft.world.entity.Entity;
16+
import net.minecraft.world.entity.EntityType;
17+
import net.minecraft.world.entity.EquipmentSlot;
18+
import net.minecraft.world.entity.LivingEntity;
19+
import net.minecraft.world.entity.Mob;
20+
import net.minecraft.world.item.Item;
21+
import net.minecraft.world.item.ItemStack;
22+
import net.minecraft.world.item.SpawnEggItem;
23+
import net.minecraft.world.level.ClipContext;
24+
import net.minecraft.world.level.ClipContext.Block;
25+
import net.minecraft.world.level.ClipContext.Fluid;
26+
import net.minecraft.world.level.Level;
27+
import net.minecraft.world.phys.AABB;
28+
import net.minecraft.world.phys.HitResult;
29+
import net.minecraft.world.phys.Vec3;
30+
31+
public final class EntityUtils {
32+
33+
/**
34+
* A cache of spawn egg colors mapped to the entity type. Populated by
35+
* {@link #getEggColors(EntityType)}.
36+
*/
37+
private static Map<EntityType<?>, Tuple<Integer, Integer>> eggColorCache = new HashMap<>();
38+
39+
/**
40+
* Calculates the distance between two entities.
41+
*
42+
* @param firstEntity The first entity to use.
43+
* @param secondEntity The second entity to use.
44+
* @return double The distance between the two entities passed.
45+
*/
46+
public static double getDistanceFromEntity (Entity firstEntity, Entity secondEntity) {
47+
48+
return MathsUtils.getDistanceBetweenPoints(firstEntity.position(), secondEntity.position());
49+
}
50+
51+
/**
52+
* Calculates the distance between an entity and a BlockPos.
53+
*
54+
* @param entity The Entity to use for the first position.
55+
* @param pos The BlockPos to use for the second position.
56+
* @return double The distance between the Entity and the BlockPos.
57+
*/
58+
public static double getDistaceFromPos (Entity entity, BlockPos pos) {
59+
60+
return MathsUtils.getDistanceBetweenPoints(entity.position(), Vec3.atCenterOf(pos));
61+
}
62+
63+
/**
64+
* Pushes an entity towards a specific direction.
65+
*
66+
* @param entityToMove The entity that you want to push.
67+
* @param direction The direction to push the entity.
68+
* @param force The amount of force to push the entity with.
69+
*/
70+
public static void pushTowards (Entity entityToMove, Direction direction, double force) {
71+
72+
pushTowards(entityToMove, entityToMove.blockPosition().relative(direction.getOpposite(), 1), force);
73+
}
74+
75+
/**
76+
* Pushes an Entity towards a BlockPos.
77+
*
78+
* @param entityToMove The entity that you want to push.
79+
* @param pos The BlockPos to push the entity towards.
80+
* @param force The amount of force to push the entity with.
81+
*/
82+
public static void pushTowards (Entity entityToMove, BlockPos pos, double force) {
83+
84+
final BlockPos entityPos = entityToMove.blockPosition();
85+
final double distanceX = (double) pos.getX() - entityPos.getX();
86+
final double distanceY = (double) pos.getY() - entityPos.getY();
87+
final double distanceZ = (double) pos.getZ() - entityPos.getZ();
88+
final double distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ);
89+
90+
if (distance > 0) {
91+
entityToMove.setDeltaMovement(new Vec3(distanceX / distance * force, distanceY / distance * force, distanceZ / distance * force));
92+
}
93+
}
94+
95+
/**
96+
* Pushes an entity towards another one.
97+
*
98+
* @param entityToMove The entity that should be pushed towards the other entity.
99+
* @param destination The destination entity, that the entity to move should be pushed
100+
* towards.
101+
* @param force The amount of force to push the entityToMove with.
102+
*/
103+
public static void pushTowards (Entity entityToMove, Entity destination, double force) {
104+
105+
final double distanceX = destination.getX() - entityToMove.getX();
106+
final double distanceY = destination.getY() - entityToMove.getY();
107+
final double distanceZ = destination.getZ() - entityToMove.getZ();
108+
final double distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ);
109+
110+
if (distance > 0) {
111+
entityToMove.setDeltaMovement(new Vec3(distanceX / distance * force, distanceY / distance * force, distanceZ / distance * force));
112+
}
113+
}
114+
115+
/**
116+
* Creates a Vector3d that represents the additional motion that would be needed to push an
117+
* entity towards a destination.
118+
*
119+
* @param entityToMove The entity to push.
120+
* @param direction The direction to push the entity.
121+
* @param force The amount of force to use.
122+
*
123+
*/
124+
public static void pushTowardsDirection (Entity entityToMove, Direction direction, double force) {
125+
126+
final BlockPos entityPos = entityToMove.blockPosition();
127+
final BlockPos destination = entityToMove.blockPosition().relative(direction.getOpposite(), 1);
128+
129+
final double distanceX = (double) destination.getX() - entityPos.getX();
130+
final double distanceY = (double) destination.getY() - entityPos.getY();
131+
final double distanceZ = (double) destination.getZ() - entityPos.getZ();
132+
final double distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ);
133+
134+
if (distance > 0) {
135+
entityToMove.setDeltaMovement(new Vec3(distanceX / distance * force, distanceY / distance * force, distanceZ / distance * force));
136+
}
137+
}
138+
139+
/**
140+
* Checks if two entities are close enough together.
141+
*
142+
* @param firstEntity The first entity to check.
143+
* @param secondEntity The second entity to check.
144+
* @param maxDistance The maximum distance that the entities can be apart.
145+
* @return boolean True if the distance between the entities are within range of the
146+
* maxDistance.
147+
*/
148+
public static boolean areEntitiesCloseEnough (Entity firstEntity, Entity secondEntity, double maxDistance) {
149+
150+
return getDistanceFromEntity(firstEntity, secondEntity) < maxDistance * maxDistance;
151+
}
152+
153+
/**
154+
* Gets a List of entities that are within the provided area.
155+
*
156+
* @param <T> The type of entities to look for.
157+
* @param entityClass The type of entity you are looking for.
158+
* @param world The world to search in.
159+
* @param pos The position to start the search around.
160+
* @param range The range of the search.
161+
* @return A List containing all entities of the specified type that are within the range.
162+
*/
163+
public static <T extends Entity> List<T> getEntitiesInArea (Class<T> entityClass, Level world, BlockPos pos, int range) {
164+
165+
return getEntitiesInArea(entityClass, world, pos, (float) range);
166+
}
167+
168+
/**
169+
* Gets a List of entities that are within the provided area.
170+
*
171+
* @param <T> The type of entities to look for.
172+
* @param entityClass The type of entity you are looking for.
173+
* @param world The world to search in.
174+
* @param pos The position to start the search around.
175+
* @param range The range of the search.
176+
* @return A List containing all entities of the specified type that are within the range.
177+
*/
178+
public static <T extends Entity> List<T> getEntitiesInArea (Class<T> entityClass, Level world, BlockPos pos, float range) {
179+
180+
return world.getEntitiesOfClass(entityClass, new AABB(pos.offset(-range, -range, -range), pos.offset(range + 1, range + 1, range + 1)));
181+
}
182+
183+
/**
184+
* A check to see if an entity is wearing a full suit of the armor. This check is based on
185+
* the class names of armor.
186+
*
187+
* @param living: The living entity to check the armor of.
188+
* @param armorClass: The class of the armor to check against.
189+
* @return boolean: True if every piece of armor the entity is wearing are the same class
190+
* as the provied armor class.
191+
*/
192+
public static boolean isWearingFullSet (Mob living, Class<Item> armorClass) {
193+
194+
for (final EquipmentSlot slot : EquipmentSlot.values()) {
195+
if (slot.getType().equals(EquipmentSlot.Type.ARMOR)) {
196+
197+
final ItemStack armor = living.getItemBySlot(slot);
198+
199+
if (armor.isEmpty() || !armor.getItem().getClass().equals(armorClass)) {
200+
return false;
201+
}
202+
}
203+
}
204+
205+
return true;
206+
}
207+
208+
/**
209+
* Performs a ray trace for the look vector of an entity.
210+
*
211+
* @param entity The entity to perform a ray trace on.
212+
* @param length The distance to cast the rays.
213+
* @param blockMode The mode used when detecting blocks.
214+
* @param fluidMode The mode used when detecting fluids.
215+
* @return An object containing the results of the ray trace.
216+
*/
217+
public static HitResult rayTrace (LivingEntity entity, double length, Block blockMode, Fluid fluidMode) {
218+
219+
final Vec3 startingPosition = new Vec3(entity.getX(), entity.getY() + entity.getEyeHeight(), entity.getZ());
220+
final Vec3 lookVector = entity.getLookAngle();
221+
final Vec3 endingPosition = startingPosition.add(lookVector.x * length, lookVector.y * length, lookVector.z * length);
222+
return entity.level.clip(new ClipContext(startingPosition, endingPosition, blockMode, fluidMode, entity));
223+
}
224+
225+
/**
226+
* Checks if an entity can be affected by fire. While fire immune entities can already
227+
* negate the effects of fire doing prechecks using this method can be used to avoid
228+
* rendering flickers or filter out these types of entities.
229+
*
230+
* @param toCheck The entity to check.
231+
* @return Whether or not this entity can be affected by fire.
232+
*/
233+
public static boolean isAffectedByFire (LivingEntity toCheck) {
234+
235+
return !toCheck.fireImmune() && !toCheck.hasEffect(MobEffects.FIRE_RESISTANCE);
236+
}
237+
238+
/**
239+
* Clears potion effect from an entity based on whether or not the effects are positive or
240+
* negative.
241+
*
242+
* @param entity The entity to remove effects from.
243+
* @param removePositive Should positive effects be cleared?
244+
* @param removeNegative Should negative effects be cleared?
245+
*/
246+
public static void clearEffects (LivingEntity entity, boolean removePositive, boolean removeNegative) {
247+
248+
final Set<MobEffect> toClear = new HashSet<>();
249+
250+
for (final MobEffectInstance effect : entity.getActiveEffects()) {
251+
252+
final boolean isGood = effect.getEffect().isBeneficial();
253+
254+
if (isGood && removePositive || !isGood && removeNegative) {
255+
256+
toClear.add(effect.getEffect());
257+
}
258+
}
259+
260+
for (final MobEffect effect : toClear) {
261+
262+
entity.removeEffect(effect);
263+
}
264+
}
265+
266+
/**
267+
* Get the egg color associated with an entity type. If the entity does not have an egg
268+
* type this will be 0 for both values.
269+
*
270+
* @param type The entity type to get a color for.
271+
* @return A Tuple containing the primary and secondary egg colors.
272+
*/
273+
public static Tuple<Integer, Integer> getEggColors (EntityType<?> type) {
274+
275+
return eggColorCache.computeIfAbsent(type, key -> {
276+
277+
SpawnEggItem item = SpawnEggItem.byId(key);
278+
279+
if (item != null) {
280+
281+
return new Tuple<>(item.getColor(0), item.getColor(1));
282+
}
283+
284+
return new Tuple<>(0, 0);
285+
});
286+
}
287+
}

0 commit comments

Comments
 (0)