Improved disguise hitbox behaviour

This commit is contained in:
Sollace 2020-09-29 19:18:25 +02:00
parent f0681adc12
commit 80b89088ce
9 changed files with 132 additions and 62 deletions

View file

@ -1,14 +1,18 @@
package com.minelittlepony.unicopia.ability;
import java.util.Optional;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.EntityDimensions;
/**
* Predicate for abilities to control what the player's physical height is.
*
* This overrides the default.
*/
public interface HeightPredicate {
public interface DimensionsPredicate {
float getTargetEyeHeight(Pony player);
float getTargetBodyHeight(Pony player);
Optional<EntityDimensions> getTargetDimensions(Pony player);
}

View file

@ -1,12 +1,14 @@
package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.Optional;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.ability.FlightPredicate;
import com.minelittlepony.unicopia.ability.HeightPredicate;
import com.minelittlepony.unicopia.ability.DimensionsPredicate;
import com.minelittlepony.unicopia.ability.magic.AttachableSpell;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Spell;
@ -17,6 +19,7 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.UParticles;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.mob.MobEntity;
@ -24,7 +27,7 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.nbt.CompoundTag;
public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Suppressable, FlightPredicate, HeightPredicate {
public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Suppressable, FlightPredicate, DimensionsPredicate {
private final Disguise disguise = new Disguise();
@ -55,6 +58,12 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
return suppressionCounter <= otherSource.getCurrentLevel();
}
@Override
public void onDestroyed(Caster<?> caster) {
super.onDestroyed(caster);
caster.getEntity().calculateDimensions();
}
@Override
public void onSuppressed(Caster<?> otherSource) {
suppressionCounter = 100;
@ -218,8 +227,8 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
}
@Override
public float getTargetBodyHeight(Pony player) {
return isSuppressed() ? -1 : disguise.getHeight();
public Optional<EntityDimensions> getTargetDimensions(Pony player) {
return isSuppressed() ? Optional.empty() : disguise.getDimensions();
}
static abstract class PlayerAccess extends PlayerEntity {

View file

@ -0,0 +1,8 @@
package com.minelittlepony.unicopia.entity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
public interface ItemWielder {
void updateItemUsage(Hand hand, ItemStack stack, int time);
}

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.entity.behaviour;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nonnull;
@ -19,6 +20,7 @@ import com.mojang.authlib.GameProfile;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.SkullBlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.entity.Flutterer;
@ -46,6 +48,8 @@ public class Disguise implements NbtSerialisable {
private List<Entity> attachments = new ArrayList<>();
private Optional<EntityDimensions> dimensions = Optional.empty();
@Nullable
private CompoundTag entityNbt;
@ -200,6 +204,10 @@ public class Disguise implements NbtSerialisable {
return -1;
}
public Optional<EntityDimensions> getDimensions() {
return dimensions = EntityBehaviour.forEntity(entity).getDimensions(entity, dimensions);
}
public boolean skipsUpdate() {
return entity instanceof FallingBlockEntity
|| entity instanceof AbstractDecorationEntity

View file

@ -1,14 +1,17 @@
package com.minelittlepony.unicopia.entity.behaviour;
import java.util.Optional;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.entity.ItemWielder;
import com.minelittlepony.unicopia.util.Registries;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.FallingBlockEntity;
@ -36,6 +39,21 @@ public class EntityBehaviour<T extends Entity> {
return entity;
}
public Optional<EntityDimensions> getDimensions(T entity, Optional<EntityDimensions> current) {
if (entity == null) {
return Optional.empty();
}
float h = entity.getHeight() - 0.1F;
float w = entity.getWidth();
if (current.isPresent() && h == current.get().height && w == current.get().width) {
return current;
}
return Optional.of(EntityDimensions.changing(entity.getHeight() - 0.1F, entity.getWidth()));
}
public void copyBaseAttributes(LivingEntity from, Entity to) {
copyBaseAttributes(from, to, Vec3d.ZERO);
}
@ -102,6 +120,9 @@ public class EntityBehaviour<T extends Entity> {
to.prevYaw = from.prevYaw;
to.horizontalSpeed = from.horizontalSpeed;
to.prevHorizontalSpeed = from.prevHorizontalSpeed;
to.horizontalCollision = from.horizontalCollision;
to.verticalCollision = from.verticalCollision;
to.setOnGround(from.isOnGround());
to.distanceTraveled = from.distanceTraveled;
@ -139,6 +160,10 @@ public class EntityBehaviour<T extends Entity> {
((AbstractSkeletonEntity)to).setAttacking(from.getItemUseTimeLeft() > 0);
}
if (to instanceof ItemWielder) {
((ItemWielder)to).updateItemUsage(from.getActiveHand(), from.getActiveItem(), from.getItemUseTimeLeft());
}
if (from.age < 100 || from instanceof PlayerEntity && ((PlayerEntity)from).isCreative()) {
to.extinguish();
}

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.entity.behaviour;
import java.util.List;
import java.util.Optional;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Spell;
@ -18,6 +19,7 @@ import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.block.entity.EnderChestBlockEntity;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.state.property.Properties;
import net.minecraft.tag.BlockTags;
@ -29,6 +31,14 @@ public class FallingBlockBehaviour extends EntityBehaviour<FallingBlockEntity> {
private static final Vec3d UP = Vec3d.of(Direction.UP.getVector());
private static final Optional<EntityDimensions> FULL_BLOCK = Optional.of(EntityDimensions.changing(1, 0.9F));
@Override
public Optional<EntityDimensions> getDimensions(FallingBlockEntity entity, Optional<EntityDimensions> current) {
return FULL_BLOCK;
}
@Override
public FallingBlockEntity onCreate(FallingBlockEntity entity, Disguise context, boolean replaceOld) {
super.onCreate(entity, context, replaceOld);

View file

@ -1,18 +1,22 @@
package com.minelittlepony.unicopia.entity.player;
import com.minelittlepony.unicopia.ability.HeightPredicate;
import java.util.Optional;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.DimensionsPredicate;
import com.minelittlepony.unicopia.ability.magic.Spell;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityPose;
public final class PlayerDimensions {
private float defaultEyeHeight;
private float defaultBodyHeight;
private float lastTargetEyeHeight;
private float lastTargetBodyHeight;
@Nullable
private EntityDimensions defaultDimensions;
@Nullable
private EntityDimensions flyingDimensions;
private final PlayerPhysics physics;
@ -23,52 +27,42 @@ public final class PlayerDimensions {
this.physics = gravity;
}
public float getActiveEyeHeight(float original) {
public float calculateActiveEyeHeight(EntityDimensions dimensions, float original) {
defaultEyeHeight = original;
return calculateTargetEyeHeightWithGravity(calculateTargetBodyHeight());
}
public EntityDimensions getDimensions(EntityPose pos, EntityDimensions dimensions) {
defaultBodyHeight = dimensions.height;
return EntityDimensions.changing(dimensions.width, calculateTargetBodyHeight());
}
boolean update() {
float targetBodyHeight = calculateTargetBodyHeight();
float targetEyeHeight = calculateTargetEyeHeightWithGravity(targetBodyHeight);
if (targetEyeHeight != lastTargetEyeHeight || targetBodyHeight != lastTargetBodyHeight) {
lastTargetBodyHeight = targetBodyHeight;
lastTargetEyeHeight = targetEyeHeight;
return true;
}
return false;
}
private float calculateTargetEyeHeightWithGravity(float targetBodyHeight) {
float height = calculateTargetEyeHeight();
if (physics.isGravityNegative() && pony.getOwner().isSneaking()) {
height += 0.2F;
}
if (physics.isGravityNegative()) {
height = targetBodyHeight - height;
if (pony.getOwner().isSneaking()) {
height += 0.2F;
}
height = dimensions.height - height;
}
return height;
}
private float calculateTargetEyeHeight() {
if (pony.hasSpell()) {
Spell effect = pony.getSpell(true);
if (!effect.isDead() && effect instanceof HeightPredicate) {
float val = ((HeightPredicate)effect).getTargetEyeHeight(pony);
if (val > 0) {
return val;
}
public EntityDimensions calculateDimensions(EntityDimensions dimensions) {
if (defaultDimensions == null || dimensions.height != defaultDimensions.height || dimensions.width != defaultDimensions.width) {
defaultDimensions = dimensions;
flyingDimensions = EntityDimensions.changing(dimensions.width, dimensions.height / 2);
}
return getPredicate().flatMap(e -> e.getTargetDimensions(pony)).orElseGet(() -> {
if (physics.isFlyingSurvival && physics.isRainboom()) {
return flyingDimensions;
}
return defaultDimensions;
});
}
private float calculateTargetEyeHeight() {
float height = getPredicate().map(e -> e.getTargetEyeHeight(pony)).orElse(-1F);
if (height > 0) {
return height;
}
if (physics.isFlyingSurvival && physics.isRainboom()) {
@ -78,22 +72,13 @@ public final class PlayerDimensions {
return defaultEyeHeight;
}
private float calculateTargetBodyHeight() {
Optional<DimensionsPredicate> getPredicate() {
if (pony.hasSpell()) {
Spell effect = pony.getSpell(true);
if (!effect.isDead() && effect instanceof HeightPredicate) {
float val = ((HeightPredicate)effect).getTargetBodyHeight(pony);
if (val > 0) {
return val;
}
if (!effect.isDead() && effect instanceof DimensionsPredicate) {
return Optional.of(((DimensionsPredicate)effect));
}
}
if (physics.isFlyingSurvival && physics.isRainboom()) {
return defaultBodyHeight / 2;
}
return defaultBodyHeight;
return Optional.empty();
}
}

View file

@ -17,14 +17,21 @@ import com.minelittlepony.unicopia.entity.PonyContainer;
import com.minelittlepony.unicopia.entity.behaviour.Disguise;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.entity.Equine;
import com.minelittlepony.unicopia.entity.ItemWielder;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
@Mixin(LivingEntity.class)
abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<?>> {
abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<?>>, ItemWielder {
@Shadow
protected ItemStack activeItemStack;
@Shadow
protected int itemUseTimeLeft;
@Shadow
private Optional<BlockPos> climbingPos;
@ -33,6 +40,9 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
private MixinLivingEntity() { super(null, null); }
@Shadow
protected abstract void setLivingFlag(int mask, boolean value);
@Override
public Equine<?> create() {
return new Creature((LivingEntity)(Object)this);
@ -108,6 +118,17 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
return get().getPhysics().calcGravity(initial);
}
@Override
public void updateItemUsage(Hand hand, ItemStack stack, int time) {
activeItemStack = stack;
itemUseTimeLeft = time;
if (!world.isClient) {
setLivingFlag(1, !stack.isEmpty());
setLivingFlag(2, hand == Hand.OFF_HAND);
}
}
@Override
protected BlockPos getLandingPos() {
if (get().getPhysics().isGravityNegative()) {

View file

@ -91,13 +91,13 @@ abstract class MixinPlayerEntity extends LivingEntity implements PonyContainer<P
at = @At("RETURN"),
cancellable = true)
private void onGetActiveEyeHeight(EntityPose pose, EntityDimensions dimensions, CallbackInfoReturnable<Float> info) {
info.setReturnValue(get().getMotion().getDimensions().getActiveEyeHeight(info.getReturnValue()));
info.setReturnValue(get().getMotion().getDimensions().calculateActiveEyeHeight(dimensions, info.getReturnValue()));
}
@Inject(method = "getDimensions(Lnet/minecraft/entity/EntityPose;)Lnet/minecraft/entity/EntityDimensions;",
at = @At("RETURN"),
cancellable = true)
public void onGetDimensions(EntityPose pose, CallbackInfoReturnable<EntityDimensions> info) {
info.setReturnValue(get().getMotion().getDimensions().getDimensions(pose, info.getReturnValue()));
info.setReturnValue(get().getMotion().getDimensions().calculateDimensions(info.getReturnValue()));
}
}