mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-30 16:28:00 +01:00
Implement shapeshifting for changelings
This commit is contained in:
parent
08aacefc26
commit
c9354d7acb
13 changed files with 386 additions and 44 deletions
|
@ -56,6 +56,10 @@ public class UClient {
|
|||
return false;
|
||||
}
|
||||
|
||||
public int getViewMode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void preInit(FMLPreInitializationEvent event) {}
|
||||
|
||||
public void init(FMLInitializationEvent event) {}
|
||||
|
|
|
@ -22,6 +22,7 @@ import net.minecraftforge.client.event.EntityViewRenderEvent;
|
|||
import net.minecraftforge.client.event.FOVUpdateEvent;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
|
||||
import net.minecraftforge.client.event.RenderLivingEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
|
@ -100,6 +101,21 @@ public class UnicopiaClient extends UClient {
|
|||
return getPlayer().getGameProfile().getId().equals(player.getGameProfile().getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewMode() {
|
||||
return Minecraft.getMinecraft().gameSettings.thirdPersonView;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@SubscribeEvent
|
||||
public static void preEntityRender(RenderLivingEvent.Pre<?> event) {
|
||||
if (event.getEntity() instanceof EntityPlayer) {
|
||||
if (PlayerSpeciesList.instance().getPlayer((EntityPlayer)event.getEntity()).isInvisible()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
|
|
|
@ -28,11 +28,18 @@ public class EffectSync<T extends EntityLivingBase> {
|
|||
NBTTagCompound comp = owned.getEntity().getDataManager().get(param);
|
||||
|
||||
if (comp == null || !comp.hasKey("effect_id")) {
|
||||
if (effect != null) {
|
||||
effect.setDead();
|
||||
effect = null;
|
||||
}
|
||||
} else {
|
||||
String id = comp.getString("effect_id");
|
||||
|
||||
if (effect == null || !effect.getName().contentEquals(id)) {
|
||||
if (effect != null) {
|
||||
effect.setDead();
|
||||
effect = null;
|
||||
}
|
||||
effect = SpellRegistry.instance().createEffectFromNBT(comp);
|
||||
} else if (owned.getEntity().world.isRemote) {
|
||||
effect.readFromNBT(comp);
|
||||
|
@ -43,6 +50,9 @@ public class EffectSync<T extends EntityLivingBase> {
|
|||
}
|
||||
|
||||
public void set(IMagicEffect effect) {
|
||||
if (this.effect != null && this.effect != effect) {
|
||||
this.effect.setDead();
|
||||
}
|
||||
this.effect = effect;
|
||||
|
||||
if (effect == null) {
|
||||
|
|
|
@ -54,6 +54,10 @@ public interface IPlayer extends ICaster<EntityPlayer>, IRaceContainer<EntityPla
|
|||
|
||||
boolean stepOnCloud();
|
||||
|
||||
boolean isInvisible();
|
||||
|
||||
void setInvisible(boolean invisible);
|
||||
|
||||
void onFall(float distance, float damageMultiplier);
|
||||
|
||||
void beforeUpdate(EntityPlayer entity);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.minelittlepony.unicopia.player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.jumpingcastle.api.Target;
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
import com.minelittlepony.unicopia.network.MsgPlayerAbility;
|
||||
|
@ -15,12 +17,11 @@ class PlayerAbilityDelegate implements IAbilityReceiver, IUpdatable<EntityPlayer
|
|||
|
||||
private final IPlayer player;
|
||||
|
||||
private boolean abilityTriggered = false;
|
||||
|
||||
private int warmup = 0;
|
||||
|
||||
private int cooldown = 0;
|
||||
|
||||
@Nullable
|
||||
private IPower<?> activeAbility = null;
|
||||
|
||||
public PlayerAbilityDelegate(IPlayer player) {
|
||||
|
@ -28,23 +29,21 @@ class PlayerAbilityDelegate implements IAbilityReceiver, IUpdatable<EntityPlayer
|
|||
}
|
||||
|
||||
boolean canSwitchStates() {
|
||||
return abilityTriggered && cooldown <= 0;
|
||||
return (warmup == 0 && cooldown == 0) || activeAbility == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tryUseAbility(IPower<?> power) {
|
||||
public synchronized void tryUseAbility(IPower<?> power) {
|
||||
if (canSwitchStates() || activeAbility != power) {
|
||||
abilityTriggered = false;
|
||||
activeAbility = power;
|
||||
warmup = 0;
|
||||
cooldown = power.getCooldownTime(player);
|
||||
warmup = power.getWarmupTime(player);
|
||||
cooldown = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tryClearAbility() {
|
||||
if (canSwitchStates() || activeAbility != null) {
|
||||
abilityTriggered = false;
|
||||
public synchronized void tryClearAbility() {
|
||||
if (canSwitchStates()) {
|
||||
activeAbility = null;
|
||||
warmup = 0;
|
||||
cooldown = 0;
|
||||
|
@ -57,34 +56,28 @@ class PlayerAbilityDelegate implements IAbilityReceiver, IUpdatable<EntityPlayer
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(EntityPlayer entity) {
|
||||
public synchronized void onUpdate(EntityPlayer entity) {
|
||||
if (activeAbility != null && activeAbility.canUse(player.getPlayerSpecies())) {
|
||||
if (!abilityTriggered) {
|
||||
if (warmup < activeAbility.getWarmupTime(player)) {
|
||||
if (warmup > 0) {
|
||||
warmup--;
|
||||
activeAbility.preApply(player);
|
||||
warmup++;
|
||||
} else if (player.isClientPlayer()) {
|
||||
if (activeAbility.canActivate(entity.getEntityWorld(), player)) {
|
||||
abilityTriggered = activateAbility(entity);
|
||||
if (!abilityTriggered) {
|
||||
activeAbility = null;
|
||||
cooldown = 0;
|
||||
}
|
||||
if (activateAbility()) {
|
||||
cooldown = activeAbility.getCooldownTime(player);
|
||||
} else {
|
||||
activeAbility = null;
|
||||
cooldown = 0;
|
||||
}
|
||||
}
|
||||
} else if (cooldown > 0) {
|
||||
activeAbility.postApply(player);
|
||||
|
||||
if (cooldown > 0 && activeAbility != null) {
|
||||
cooldown--;
|
||||
activeAbility.postApply(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(NBTTagCompound compound) {
|
||||
compound.setBoolean("triggered", abilityTriggered);
|
||||
compound.setInteger("warmup", warmup);
|
||||
compound.setInteger("cooldown", cooldown);
|
||||
|
||||
|
@ -95,10 +88,9 @@ class PlayerAbilityDelegate implements IAbilityReceiver, IUpdatable<EntityPlayer
|
|||
|
||||
@Override
|
||||
public void readFromNBT(NBTTagCompound compound) {
|
||||
activeAbility = null;
|
||||
abilityTriggered = compound.getBoolean("triggered");
|
||||
warmup = compound.getInteger("warmup");
|
||||
cooldown = compound.getInteger("cooldown");
|
||||
activeAbility = null;
|
||||
|
||||
if (compound.hasKey("activeAbility")) {
|
||||
PowersRegistry.instance().getPowerFromName(compound.getString("activeAbility")).ifPresent(p -> {
|
||||
|
@ -107,11 +99,15 @@ class PlayerAbilityDelegate implements IAbilityReceiver, IUpdatable<EntityPlayer
|
|||
}
|
||||
}
|
||||
|
||||
protected boolean activateAbility(EntityPlayer entity) {
|
||||
IData data = activeAbility.tryActivate(entity, entity.getEntityWorld());
|
||||
protected boolean activateAbility() {
|
||||
if (activeAbility == null || !activeAbility.canActivate(player.getWorld(), player)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IData data = activeAbility.tryActivate(player.getOwner(), player.getWorld());
|
||||
|
||||
if (data != null) {
|
||||
Unicopia.channel.send(new MsgPlayerAbility(entity, activeAbility, data), Target.SERVER);
|
||||
Unicopia.channel.send(new MsgPlayerAbility(player.getOwner(), activeAbility, data), Target.SERVER);
|
||||
}
|
||||
|
||||
return data != null;
|
||||
|
|
|
@ -69,6 +69,8 @@ class PlayerCapabilities implements IPlayer {
|
|||
|
||||
private boolean dirty = false;
|
||||
|
||||
private boolean invisible = false;
|
||||
|
||||
PlayerCapabilities(EntityPlayer player) {
|
||||
setOwner(player);
|
||||
|
||||
|
@ -128,6 +130,16 @@ class PlayerCapabilities implements IPlayer {
|
|||
getOwner().getDataManager().set(ENERGY, Math.max(0, energy));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvisible() {
|
||||
return invisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInvisible(boolean invisible) {
|
||||
this.invisible = invisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAffinity getAffinity() {
|
||||
return SpellAffinity.NEUTRAL;
|
||||
|
@ -195,9 +207,6 @@ class PlayerCapabilities implements IPlayer {
|
|||
gravity.onUpdate(entity);
|
||||
|
||||
if (hasEffect()) {
|
||||
if (!getPlayerSpecies().canCast()) {
|
||||
setEffect(null);
|
||||
} else {
|
||||
if (entity.getEntityWorld().isRemote) {
|
||||
getEffect().renderOnPerson(this);
|
||||
}
|
||||
|
@ -206,7 +215,6 @@ class PlayerCapabilities implements IPlayer {
|
|||
setEffect(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addExertion(-1);
|
||||
addEnergy(-1);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.minelittlepony.unicopia.power;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
import com.minelittlepony.unicopia.input.IKeyBind;
|
||||
import com.minelittlepony.unicopia.particle.Particles;
|
||||
|
@ -99,6 +101,7 @@ public interface IPower<T extends IData> extends IKeyBind {
|
|||
* @param w The player's world
|
||||
* @return Data to be sent, or null if activation failed
|
||||
*/
|
||||
@Nullable
|
||||
T tryActivate(EntityPlayer player, World w);
|
||||
|
||||
Class<T> getPackageType();
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package com.minelittlepony.unicopia.power;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import com.minelittlepony.unicopia.UParticles;
|
||||
import com.minelittlepony.unicopia.player.IPlayer;
|
||||
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
||||
import com.minelittlepony.unicopia.power.data.Hit;
|
||||
import com.minelittlepony.unicopia.spell.IMagicEffect;
|
||||
import com.minelittlepony.unicopia.spell.SpellDisguise;
|
||||
import com.minelittlepony.util.vector.VecHelper;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class PowerDisguise extends PowerFeed {
|
||||
|
||||
@Override
|
||||
public String getKeyName() {
|
||||
return "unicopia.power.diguise";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getKeyCode() {
|
||||
return Keyboard.KEY_P;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Hit tryActivate(EntityPlayer player, World w) {
|
||||
return new Hit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(EntityPlayer player, Hit data) {
|
||||
Entity looked = VecHelper.getLookedAtEntity(player, 17);
|
||||
|
||||
IPlayer iplayer = PlayerSpeciesList.instance().getPlayer(player);
|
||||
|
||||
player.world.playSound(null, player.getPosition(), SoundEvents.E_PARROT_IM_POLAR_BEAR, SoundCategory.PLAYERS, 1.4F, 0.4F);
|
||||
|
||||
IMagicEffect effect = iplayer.getEffect();
|
||||
if (effect instanceof SpellDisguise && !effect.getDead()) {
|
||||
((SpellDisguise)effect).setDisguise(looked);
|
||||
} else if (looked != null) {
|
||||
iplayer.setEffect(new SpellDisguise().setDisguise(looked));
|
||||
}
|
||||
|
||||
iplayer.sendCapabilities(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preApply(IPlayer player) {
|
||||
player.addEnergy(2);
|
||||
IPower.spawnParticles(UParticles.MAGIC_PARTICLE, player, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(IPlayer player) {
|
||||
player.setEnergy(0);
|
||||
IPower.spawnParticles(UParticles.MAGIC_PARTICLE, player, 5);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ package com.minelittlepony.unicopia.power;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
|
@ -51,6 +53,7 @@ public class PowerFeed implements IPower<Hit> {
|
|||
return playerSpecies == Race.CHANGELING;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Hit tryActivate(EntityPlayer player, World w) {
|
||||
if (player.getHealth() < player.getMaxHealth() || player.canEat(false)) {
|
||||
|
|
|
@ -31,6 +31,7 @@ public class PowersRegistry {
|
|||
registerPower(new PowerGrow());
|
||||
registerPower(new PowerFeed());
|
||||
registerPower(new PowerCarry());
|
||||
registerPower(new PowerDisguise());
|
||||
}
|
||||
|
||||
public boolean hasRegisteredPower(int keyCode) {
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
package com.minelittlepony.unicopia.spell;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
import com.minelittlepony.unicopia.UClient;
|
||||
import com.minelittlepony.unicopia.player.IPlayer;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public class SpellDisguise extends AbstractSpell {
|
||||
|
||||
@Nonnull
|
||||
private String entityId = "";
|
||||
|
||||
@Nullable
|
||||
private Entity entity;
|
||||
|
||||
@Nullable
|
||||
private NBTTagCompound entityNbt;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "disguise";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTint() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public SpellDisguise setDisguise(@Nullable Entity entity) {
|
||||
this.entityNbt = null;
|
||||
|
||||
if (this.entity != null) {
|
||||
this.entity.setDead();
|
||||
}
|
||||
|
||||
this.entity = null;
|
||||
|
||||
this.entityId = "";
|
||||
|
||||
if (entity != null) {
|
||||
this.entityId = EntityList.getKey(entity).toString();
|
||||
this.entityNbt = entity.writeToNBT(new NBTTagCompound());
|
||||
this.entityNbt.setString("id", entityId);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(ICaster<?> source, int level) {
|
||||
if (entity == null && entityNbt != null) {
|
||||
entity = EntityList.createEntityFromNBT(entityNbt, source.getWorld());
|
||||
|
||||
if (entity != null && source.getWorld().isRemote) {
|
||||
source.getWorld().spawnEntity(entity);
|
||||
}
|
||||
|
||||
entityNbt = null;
|
||||
}
|
||||
|
||||
EntityLivingBase owner = source.getOwner();
|
||||
|
||||
if (owner == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entity != null) {
|
||||
if (entity instanceof EntityLiving) {
|
||||
EntityLiving l = (EntityLiving)entity;
|
||||
|
||||
l.setNoAI(true);
|
||||
|
||||
l.rotationYawHead = owner.rotationYawHead;
|
||||
l.prevRotationYawHead = owner.prevRotationYawHead;
|
||||
l.renderYawOffset = owner.renderYawOffset;
|
||||
l.prevRenderYawOffset = owner.prevRenderYawOffset;
|
||||
|
||||
l.limbSwing = owner.limbSwing;
|
||||
l.limbSwingAmount = owner.limbSwingAmount;
|
||||
l.prevLimbSwingAmount = owner.prevLimbSwingAmount;
|
||||
|
||||
l.swingingHand = owner.swingingHand;
|
||||
l.swingProgress = owner.swingProgress;
|
||||
l.swingProgressInt = owner.swingProgressInt;
|
||||
l.isSwingInProgress = owner.isSwingInProgress;
|
||||
|
||||
for (EntityEquipmentSlot i : EntityEquipmentSlot.values()) {
|
||||
l.setItemStackToSlot(i, owner.getItemStackFromSlot(i));
|
||||
}
|
||||
|
||||
if (l.world.rand.nextInt(1000) < l.livingSoundTime++) {
|
||||
l.playLivingSound();
|
||||
l.livingSoundTime = -l.getTalkInterval();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
entity.copyLocationAndAnglesFrom(owner);
|
||||
|
||||
entity.setNoGravity(true);
|
||||
|
||||
entity.prevPosX = owner.prevPosX;
|
||||
entity.prevPosY = owner.prevPosY;
|
||||
entity.prevPosZ = owner.prevPosZ;
|
||||
|
||||
entity.motionX = owner.motionX;
|
||||
entity.motionY = owner.motionY;
|
||||
entity.motionZ = owner.motionZ;
|
||||
|
||||
entity.prevRotationPitch = owner.prevRotationPitch;
|
||||
entity.prevRotationYaw = owner.prevRotationYaw;
|
||||
|
||||
entity.distanceWalkedOnStepModified = owner.distanceWalkedOnStepModified;
|
||||
entity.distanceWalkedModified = owner.distanceWalkedModified;
|
||||
entity.prevDistanceWalkedModified = owner.prevDistanceWalkedModified;
|
||||
|
||||
owner.height = entity.height;
|
||||
|
||||
entity.setSneaking(owner.isSneaking());
|
||||
|
||||
entity.setInvisible(false);
|
||||
|
||||
if (source instanceof IPlayer) {
|
||||
((IPlayer) source).setInvisible(true);
|
||||
}
|
||||
owner.setInvisible(true);
|
||||
|
||||
if (owner instanceof EntityPlayer) {
|
||||
EntityPlayer player = (EntityPlayer)owner;
|
||||
|
||||
player.eyeHeight = entity.getEyeHeight();
|
||||
|
||||
if (UClient.instance().isClientPlayer(player)) {
|
||||
entity.setAlwaysRenderNameTag(false);
|
||||
entity.setCustomNameTag("");
|
||||
|
||||
if (UClient.instance().getViewMode() == 0) {
|
||||
entity.setInvisible(true);
|
||||
entity.posY = -10;
|
||||
}
|
||||
} else {
|
||||
entity.setAlwaysRenderNameTag(true);
|
||||
entity.setCustomNameTag(player.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (!(source instanceof IPlayer) || ((IPlayer) source).getPlayerSpecies() == Race.CHANGELING) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
owner.setInvisible(false);
|
||||
|
||||
if (source instanceof IPlayer) {
|
||||
((IPlayer) source).setInvisible(false);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDead() {
|
||||
super.setDead();
|
||||
|
||||
if (entity != null) {
|
||||
entity.setDead();
|
||||
entity = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(ICaster<?> source, int level) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(NBTTagCompound compound) {
|
||||
|
||||
compound.setString("entityId", entityId);
|
||||
compound.setBoolean("dead", getDead());
|
||||
|
||||
if (entityNbt != null) {
|
||||
compound.setTag("entity", entityNbt);
|
||||
} else if (entity != null) {
|
||||
NBTTagCompound entityTag = new NBTTagCompound();
|
||||
entity.writeToNBT(entityTag);
|
||||
entityTag.setString("id", entityId);
|
||||
|
||||
compound.setTag("entity", entityTag);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(NBTTagCompound compound) {
|
||||
String newId = compound.getString("entityId");
|
||||
|
||||
if (!newId.contentEquals(entityId)) {
|
||||
entityNbt = null;
|
||||
|
||||
if (entity != null) {
|
||||
entity.setDead();
|
||||
entity = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (compound.hasKey("entity")) {
|
||||
entityId = newId;
|
||||
|
||||
entityNbt = compound.getCompoundTag("entity");
|
||||
|
||||
if (entity != null) {
|
||||
entity.readFromNBT(entityNbt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ public class SpellRegistry {
|
|||
registerSpell(SpellIce::new);
|
||||
registerSpell(SpellPortal::new);
|
||||
registerSpell(SpellVortex::new);
|
||||
registerSpell(SpellDisguise::new);
|
||||
}
|
||||
|
||||
public IMagicEffect getSpellFromName(String name) {
|
||||
|
|
|
@ -38,6 +38,7 @@ public class VecHelper {
|
|||
/**
|
||||
* Gets the entity the player is currently looking at, or null.
|
||||
*/
|
||||
@Nullable
|
||||
public static Entity getLookedAtEntity(EntityLivingBase e, int reach) {
|
||||
RayTraceResult objectMouseOver = getObjectMouseOver(e, reach, 1);
|
||||
|
||||
|
|
Loading…
Reference in a new issue