Disguised changelings will now have the appropriate collission boxes for whatever block/boat/minecraft they disguise themselves as

This commit is contained in:
Sollace 2020-10-10 16:27:07 +02:00
parent f14ab56d54
commit d29cc60d01
4 changed files with 92 additions and 1 deletions

View file

@ -4,6 +4,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Predicate;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -13,11 +15,13 @@ import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.CasterUtils; import com.minelittlepony.unicopia.ability.magic.CasterUtils;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.projectile.ProjectileUtil;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import net.minecraft.block.ShapeContext;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.SkullBlockEntity; import net.minecraft.block.entity.SkullBlockEntity;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@ -35,6 +39,12 @@ import net.minecraft.entity.mob.VexEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ShulkerBulletEntity; import net.minecraft.entity.projectile.ShulkerBulletEntity;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.function.BooleanBiFunction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.WorldAccess;
public class Disguise implements NbtSerialisable { public class Disguise implements NbtSerialisable {
@ -298,4 +308,40 @@ public class Disguise implements NbtSerialisable {
return entityNbt; return entityNbt;
} }
void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output) {
getCollissionShapes(getAppearance(), context, output);
getAttachments().forEach(e -> getCollissionShapes(e, context, output));
}
private static void getCollissionShapes(Entity entity, ShapeContext context, Consumer<VoxelShape> output) {
if (entity.method_30948()) {
output.accept(VoxelShapes.cuboid(entity.getBoundingBox()));
} else if (entity instanceof FallingBlockEntity) {
BlockPos pos = entity.getBlockPos();
output.accept(((FallingBlockEntity) entity).getBlockState()
.getCollisionShape(entity.world, entity.getBlockPos(), context)
.offset(pos.getX(), pos.getY(), pos.getZ())
);
}
}
public static List<VoxelShape> getColissonShapes(@Nullable Entity entity, WorldAccess world, Box box, Predicate<Entity> predicate) {
List<VoxelShape> shapes = new ArrayList<>();
ShapeContext ctx = entity == null ? ShapeContext.absent() : ShapeContext.of(entity);
VoxelShape entityShape = VoxelShapes.cuboid(box.expand(1.0E-6D));
world.getOtherEntities(entity, box.expand(0.5), predicate.and(e -> {
CasterUtils.toCaster(e).flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false)).ifPresent(p -> {
p.getDisguise().getCollissionShapes(ctx, shape -> {
if (!shape.isEmpty() && VoxelShapes.matchesAnywhere(shape, entityShape, BooleanBiFunction.AND)) {
shapes.add(shape);
}
});
});
return false;
}));
return shapes;
}
} }

View file

@ -11,6 +11,7 @@ import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.ability.magic.CasterUtils;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
import com.minelittlepony.unicopia.entity.Creature; import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.PonyContainer; import com.minelittlepony.unicopia.entity.PonyContainer;
@ -69,6 +70,18 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
} }
} }
@Inject(method = "isPushable()Z", at = @At("HEAD"), cancellable = true)
private void onIsPushable(CallbackInfoReturnable<Boolean> info) {
CasterUtils.toCaster(this)
.flatMap(c -> c.getSpellOrEmpty(DisguiseSpell.class, false))
.map(DisguiseSpell::getDisguise)
.map(Disguise::getAppearance)
.filter(Entity::isPushable)
.ifPresent(v -> {
info.setReturnValue(false);
});
}
@Inject(method = "canSee(Lnet/minecraft/entity/Entity;)Z", at = @At("HEAD"), cancellable = true) @Inject(method = "canSee(Lnet/minecraft/entity/Entity;)Z", at = @At("HEAD"), cancellable = true)
private void onCanSee(Entity other, CallbackInfoReturnable<Boolean> info) { private void onCanSee(Entity other, CallbackInfoReturnable<Boolean> info) {
if (get().isInvisible()) { if (get().isInvisible()) {

View file

@ -0,0 +1,31 @@
package com.minelittlepony.unicopia.mixin;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import com.minelittlepony.unicopia.entity.behaviour.Disguise;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.Box;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
@Mixin(World.class)
abstract class MixinWorld implements WorldAccess {
@Override
public Stream<VoxelShape> getEntityCollisions(@Nullable Entity entity, Box box, Predicate<Entity> predicate) {
if (box.getAverageSideLength() >= 1.0E-7D) {
List<VoxelShape> shapes = Disguise.getColissonShapes(entity, this, box, predicate);
if (!shapes.isEmpty()) {
return Stream.concat(shapes.stream(), WorldAccess.super.getEntityCollisions(entity, box, predicate));
}
}
return WorldAccess.super.getEntityCollisions(entity, box, predicate);
}
}

View file

@ -17,7 +17,8 @@
"MixinServerPlayerEntity", "MixinServerPlayerEntity",
"MixinSheepEntity", "MixinSheepEntity",
"MixinShulkerEntity", "MixinShulkerEntity",
"MixinTargetPredicate" "MixinTargetPredicate",
"MixinWorld"
], ],
"client": [ "client": [
"client.MixinCamera", "client.MixinCamera",