A long list of fixes for disguises

This commit is contained in:
Sollace 2020-09-24 14:49:02 +02:00
parent 9ba807b3d5
commit f08850e7c2
20 changed files with 275 additions and 79 deletions

View file

@ -52,7 +52,7 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
if (looked instanceof PlayerEntity) {
looked = Pony.of((PlayerEntity)looked)
.getSpell(DisguiseSpell.class)
.getSpellOrEmpty(DisguiseSpell.class)
.map(DisguiseSpell::getDisguise)
.orElse(looked);
}
@ -64,7 +64,7 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
player.getEntityWorld().playSound(null, player.getBlockPos(), SoundEvents.ENTITY_PARROT_IMITATE_RAVAGER, SoundCategory.PLAYERS, 1.4F, 0.4F);
iplayer.getSpell(DisguiseSpell.class).orElseGet(() -> {
iplayer.getSpellOrEmpty(DisguiseSpell.class).orElseGet(() -> {
DisguiseSpell disc = new DisguiseSpell();
iplayer.setSpell(disc);

View file

@ -43,7 +43,7 @@ public class UnicornCastingAbility implements Ability<Hit> {
public void apply(Pony player, Hit data) {
if (player.hasSpell()) {
String current = player.getSpell().getName();
String current = player.getSpell(true).getName();
player.setSpell(Streams.stream(player.getOwner().getItemsHand())
.map(SpellRegistry::getKeyFromStack)
.filter(i -> i != null && !current.equals(i))

View file

@ -43,27 +43,22 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
* Returns null if no such effect exists for this caster.
*/
@Nullable
default <T> T getSpell(@Nullable Class<T> type, boolean update) {
default <T extends Spell> T getSpell(@Nullable Class<T> type, boolean update) {
return getPrimarySpellSlot().get(type, update);
}
/**
* Gets the active effect for this caster updating it if needed.
*/
@Nullable
default Spell getSpell() {
return getSpell(true);
default <T extends Spell> Optional<T> getSpellOrEmpty(Class<T> type, boolean update) {
return getPrimarySpellSlot().getOrEmpty(type, update);
}
@SuppressWarnings("unchecked")
default <T extends Spell> Optional<T> getSpell(Class<T> type) {
Spell effect = getSpell();
if (effect == null || effect.isDead() || !type.isAssignableFrom(effect.getClass())) {
return Optional.empty();
}
return Optional.of((T)effect);
/**
* Gets the active effect for this caster updating it if needed.
*/
default <T extends Spell> Optional<T> getSpellOrEmpty(Class<T> type) {
return getSpellOrEmpty(type, true);
}
/**

View file

@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.ability.magic;
/**
* Magic effects that can be suppressed by other nearby effects.
*/
public interface Suppressable {
public interface Suppressable extends Spell {
/**
* Returns true if this spell is currently still suppressed.

View file

@ -1,7 +1,6 @@
package com.minelittlepony.unicopia.ability.magic.spell;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -16,6 +15,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.CasterUtils;
import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.Suppressable;
import com.minelittlepony.unicopia.entity.behaviour.EntityBehaviour;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.UParticles;
@ -41,7 +41,6 @@ import net.minecraft.entity.passive.TameableEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.entity.projectile.ShulkerBulletEntity;
import net.minecraft.entity.vehicle.MinecartEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
@ -158,6 +157,7 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
onEntityLoaded(source);
}
@SuppressWarnings("unchecked")
protected void checkAndCreateDisguiseEntity(Caster<?> source) {
if (entity == null && entityNbt != null) {
CompoundTag nbt = entityNbt;
@ -173,11 +173,20 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
nbt.getString("playerName")
)), source)).start();
} else {
entity = EntityType.loadEntityWithPassengers(nbt, source.getWorld(), e -> {
e.extinguish();
if (source.isClient()) {
entity = EntityType.fromTag(nbt).map(type -> type.create(source.getWorld())).orElse(null);
EntityBehaviour.forEntity(entity).ifPresent(behaviour -> {
((EntityBehaviour<Entity>)behaviour).onCreate(entity);
});
} else {
entity = EntityType.loadEntityWithPassengers(nbt, source.getWorld(), e -> {
EntityBehaviour.forEntity(e).ifPresent(behaviour -> {
((EntityBehaviour<Entity>)behaviour).onCreate(e);
});
return e;
});
return e;
});
}
}
onEntityLoaded(source);
@ -185,6 +194,8 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
}
protected void onEntityLoaded(Caster<?> source) {
source.getEntity().calculateDimensions();
if (entity == null) {
return;
}
@ -363,9 +374,6 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
}
entity.noClip = true;
//entity.updateBlocked = true;
//entity.getEntityData().setBoolean("disguise", true);
if (entity instanceof MobEntity) {
((MobEntity)entity).setAiDisabled(true);
@ -380,39 +388,9 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
entity.tick();
}
if (entity instanceof ShulkerEntity) {
ShulkerEntity shulker = ((ShulkerEntity)entity);
shulker.yaw = 0;
shulker.prevHeadYaw = 0;
shulker.headYaw = 0;
shulker.prevBodyYaw = 0;
shulker.bodyYaw = 0;
shulker.setAttachedBlock(null);
if (source.isClient() && source instanceof Pony) {
//Pony player = (Pony)source;
float peekAmount = 30;
//if (!owner.isSneaking()) {
//Math.sqrt(Entity.squaredHorizontalLength(owner.getVelocity()));
//peekAmount = (float)MathHelper.clamp(speed * 30, 0, 1);
//}
//peekAmount = player.getInterpolator().interpolate("peek", peekAmount, 5);
shulker.setPeekAmount((int)peekAmount);
}
}
if (entity instanceof MinecartEntity) {
entity.yaw += 90;
entity.pitch = 0;
}
EntityBehaviour.forEntity(entity).ifPresent(b -> {
((EntityBehaviour<Entity>)b).update(source, entity);
});
if (source instanceof Pony) {
Pony player = (Pony)source;
@ -487,8 +465,14 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
entityNbt = compound.getCompound("entity");
compound.getString("entityData");
if (entity != null) {
entity.fromTag(entityNbt);
try {
entity.fromTag(entityNbt);
} catch (Exception ignored) {
// Mojang pls
}
}
}
}

View file

@ -82,7 +82,7 @@ public class DisguiseCommand {
static int reveal(ServerCommandSource source, PlayerEntity player) {
Pony iplayer = Pony.of(player);
iplayer.getSpell(DisguiseSpell.class).ifPresent(disguise -> {
iplayer.getSpellOrEmpty(DisguiseSpell.class).ifPresent(disguise -> {
disguise.onDestroyed(iplayer);
});

View file

@ -98,7 +98,7 @@ public class Creature implements Equine<LivingEntity>, Caster<LivingEntity> {
@Override
public void toNBT(CompoundTag compound) {
Spell effect = getSpell();
Spell effect = getSpell(true);
if (effect != null) {
compound.put("effect", SpellRegistry.toNBT(effect));

View file

@ -0,0 +1,17 @@
package com.minelittlepony.unicopia.entity.behaviour;
import com.minelittlepony.unicopia.ability.magic.Caster;
import net.minecraft.entity.mob.CreeperEntity;
public class CreeperBehaviour extends EntityBehaviour<CreeperEntity> {
@Override
public void update(Caster<?> source, CreeperEntity entity) {
if (source.getEntity().isSneaking()) {
entity.setFuseSpeed(1);
} else {
entity.setFuseSpeed(-1);
entity.setTarget(null);
entity.getVisibilityCache().clear();
}
}
}

View file

@ -0,0 +1,44 @@
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.util.Registries;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
public abstract class EntityBehaviour<T extends Entity> {
private static final Registry<EntityBehaviour<?>> REGISTRY = Registries.createSimple(new Identifier("unicopia", "entity_behaviour"));
public abstract void update(Caster<?> source, T entity);
public void onCreate(T entity) {
entity.extinguish();
}
public static <T extends Entity> void register(Supplier<EntityBehaviour<T>> behaviour, EntityType<?>... types) {
for (EntityType<?> type : types) {
Registry.register(REGISTRY, EntityType.getId(type), behaviour.get());
}
}
public static Optional<EntityBehaviour<?>> forEntity(@Nullable Entity entity) {
if (entity == null) {
return Optional.empty();
}
return REGISTRY.getOrEmpty(EntityType.getId(entity.getType()));
}
static {
register(ShulkerBehaviour::new, EntityType.SHULKER);
register(CreeperBehaviour::new, EntityType.CREEPER);
register(MinecartBehaviour::new, EntityType.CHEST_MINECART, EntityType.COMMAND_BLOCK_MINECART, EntityType.FURNACE_MINECART, EntityType.HOPPER_MINECART, EntityType.MINECART, EntityType.SPAWNER_MINECART, EntityType.TNT_MINECART);
}
}

View file

@ -0,0 +1,38 @@
package com.minelittlepony.unicopia.entity.behaviour;
import com.minelittlepony.unicopia.ability.magic.Caster;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.sound.MovingMinecartSoundInstance;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
public class MinecartBehaviour extends EntityBehaviour<AbstractMinecartEntity> {
@Override
public void onCreate(AbstractMinecartEntity entity) {
super.onCreate(entity);
if (entity.world.isClient) {
MinecraftClient.getInstance().getSoundManager().play(new MovingMinecartSoundInstance(entity));
}
}
@Override
public void update(Caster<?> source, AbstractMinecartEntity entity) {
entity.yaw -= 90;
entity.prevYaw -= 90;
entity.pitch = 0;
entity.prevPitch = 0;
if (source.getEntity() instanceof LivingEntity) {
int hurt = ((LivingEntity)source.getEntity()).hurtTime;
if (hurt > 0) {
entity.setDamageWobbleTicks(hurt);
entity.setDamageWobbleStrength(1);
entity.setDamageWobbleSide(20 + (int)source.getEntity().fallDistance / 10);
}
}
}
}

View file

@ -0,0 +1,47 @@
package com.minelittlepony.unicopia.entity.behaviour;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.mixin.MixinShulkerEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.ShulkerEntity;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.math.MathHelper;
public class ShulkerBehaviour extends EntityBehaviour<ShulkerEntity> {
@Override
public void update(Caster<?> source, ShulkerEntity shulker) {
shulker.yaw = 0;
shulker.prevBodyYaw = 0;
shulker.bodyYaw = 0;
shulker.setAttachedBlock(null);
if (source instanceof Pony) {
Pony player = (Pony)source;
float peekAmount = 30;
double speed = !source.getEntity().isSneaking() ? 0.29 : 0;
speed += Math.sqrt(Entity.squaredHorizontalLength(source.getEntity().getVelocity())) * 2;
peekAmount = (float)MathHelper.clamp(speed, 0, 1);
peekAmount = ((Pony)source).getInterpolator().interpolate("peek", peekAmount, 5);
MixinShulkerEntity mx = (MixinShulkerEntity)shulker;
mx.setPrevOpenProgress(mx.getOpenProgress());
mx.setOpenProgress(peekAmount);
if (player.sneakingChanged()) {
shulker.setPeekAmount((int)(peekAmount / 0.01F));
} else if (peekAmount > 0.2 && shulker.getPeekAmount() == 0) {
if (shulker.isAlive() && shulker.world.random.nextInt(1000) < shulker.ambientSoundChance++) {
shulker.ambientSoundChance = -shulker.getMinAmbientSoundDelay();
shulker.playSound(SoundEvents.ENTITY_SHULKER_AMBIENT, 1, 1);
}
}
}
}
}

View file

@ -62,7 +62,7 @@ public final class PlayerDimensions {
private float calculateTargetEyeHeight() {
if (pony.hasSpell()) {
Spell effect = pony.getSpell();
Spell effect = pony.getSpell(true);
if (!effect.isDead() && effect instanceof HeightPredicate) {
float val = ((HeightPredicate)effect).getTargetEyeHeight(pony);
if (val > 0) {
@ -80,7 +80,7 @@ public final class PlayerDimensions {
private float calculateTargetBodyHeight() {
if (pony.hasSpell()) {
Spell effect = pony.getSpell();
Spell effect = pony.getSpell(true);
if (!effect.isDead() && effect instanceof HeightPredicate) {
float val = ((HeightPredicate)effect).getTargetBodyHeight(pony);
if (val > 0) {

View file

@ -48,7 +48,7 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
}
if (pony.hasSpell()) {
Spell effect = pony.getSpell();
Spell effect = pony.getSpell(true);
if (!effect.isDead() && effect instanceof FlightPredicate) {
return ((FlightPredicate)effect).checkCanFly(pony);
}

View file

@ -73,6 +73,7 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
private boolean dirty;
private boolean speciesSet;
private boolean speciesPersisted;
private boolean prevSneaking;
@Nullable
private Race clientPreferredRace;
@ -101,6 +102,10 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
return Race.fromId(getOwner().getDataTracker().get(RACE));
}
public boolean sneakingChanged() {
return entity.isSneaking() != prevSneaking;
}
@Override
public void setSpecies(Race race) {
race = race.validate(entity);
@ -245,6 +250,8 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
if (dirty) {
sendCapabilities(true);
}
prevSneaking = entity.isSneaking();
}
public float onImpact(float distance) {
@ -265,7 +272,7 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
@Override
public boolean onProjectileImpact(ProjectileEntity projectile) {
if (hasSpell()) {
Spell effect = getSpell();
Spell effect = getSpell(true);
if (!effect.isDead() && effect.handleProjectileImpact(projectile)) {
return true;
}
@ -323,7 +330,7 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
compound.put("powers", powers.toNBT());
compound.put("gravity", gravity.toNBT());
Spell effect = getSpell();
Spell effect = getSpell(true);
if (effect != null) {
compound.put("effect", SpellRegistry.toNBT(effect));
@ -346,7 +353,7 @@ public class Pony implements Caster<PlayerEntity>, Equine<PlayerEntity>, Transmi
@Override
public void copyFrom(Pony oldPlayer) {
speciesPersisted = oldPlayer.speciesPersisted;
setSpell(oldPlayer.getSpell());
setSpell(oldPlayer.getSpell(true));
setSpecies(oldPlayer.getSpecies());
setDirty();
}

View file

@ -0,0 +1,18 @@
package com.minelittlepony.unicopia.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.entity.mob.ShulkerEntity;
@Mixin(ShulkerEntity.class)
public interface MixinShulkerEntity {
@Accessor
float getOpenProgress();
@Accessor
void setOpenProgress(float value);
@Accessor
float getPrevOpenProgress();
@Accessor
void setPrevOpenProgress(float value);
}

View file

@ -0,0 +1,30 @@
package com.minelittlepony.unicopia.mixin;
import javax.annotation.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
import com.minelittlepony.unicopia.entity.Equine;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.TargetPredicate;
@Mixin(TargetPredicate.class)
abstract class MixinTargetPredicate {
@Inject(method = "test", at = @At("HEAD"), cancellable = true)
public void onTest(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> info) {
Equine<?> eq = Equine.of(targetEntity);
if (eq instanceof Pony) {
((Pony)eq).getSpellOrEmpty(DisguiseSpell.class).ifPresent(spell -> {
if (spell.getDisguise() == baseEntity) {
info.setReturnValue(false);
}
});
}
}
}

View file

@ -57,7 +57,7 @@ abstract class MixinEntityRenderDispatcher {
}
((EntityRenderDispatcher)(Object)this).render(e, x, y, z, yaw, tickDelta, matrices, vertexConsumers, light);
((EntityRenderDispatcher)(Object)this).render(e, x, y, z, e.yaw, tickDelta, matrices, vertexConsumers, light);
}
}

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.network;
import java.util.Optional;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.magic.Caster;
@ -54,8 +56,18 @@ public class EffectSync {
return effect != null;
}
public <T extends Spell> Optional<T> getOrEmpty(Class<T> type, boolean update) {
T effect = get(type, update);
if (effect == null || effect.isDead()) {
return Optional.empty();
}
return Optional.of(effect);
}
@SuppressWarnings("unchecked")
public <E> E get(Class<E> type, boolean update) {
public <E extends Spell> E get(Class<E> type, boolean update) {
if (!update) {
if (effect == null || type == null || type.isAssignableFrom(effect.getClass())) {
return (E)effect;

View file

@ -111,7 +111,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
@Override
public Affinity getAffinity() {
return hasSpell() ? Affinity.NEUTRAL : getSpell().getAffinity();
return hasSpell() ? Affinity.NEUTRAL : getSpell(true).getAffinity();
}
@Override
@ -178,14 +178,16 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
lastBlockPos = getBlockPos();
}
if (getSpell().isDead()) {
Spell spell = getSpell(true);
if (spell.isDead()) {
remove();
} else {
getSpell().update(this);
}
spell.update(this);
if (world.isClient()) {
getSpell().render(this);
if (world.isClient()) {
spell.render(this);
}
}
}
@ -247,7 +249,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
super.writeCustomDataToTag(compound);
if (hasSpell()) {
compound.put("effect", SpellRegistry.toNBT(getSpell()));
compound.put("effect", SpellRegistry.toNBT(getSpell(true)));
}
}
@ -266,7 +268,7 @@ public class MagicProjectileEntity extends ThrownItemEntity implements Magical,
protected void onHitBlock(BlockHitResult hit) {
if (hasSpell()) {
Spell effect = getSpell();
Spell effect = getSpell(true);
if (effect instanceof ThrowableSpell) {
((ThrowableSpell)effect).onImpact(this, hit.getBlockPos(), world.getBlockState(hit.getBlockPos()));

View file

@ -12,7 +12,9 @@
"MixinLivingEntity",
"MixinPlayerEntity",
"MixinProjectileEntity",
"MixinServerPlayerEntity"
"MixinServerPlayerEntity",
"MixinShulkerEntity",
"MixinTargetPredicate"
],
"client": [
"client.MixinCamera",