When disguised as doors or beds, make sure to render the entire block

This commit is contained in:
Sollace 2020-09-27 15:11:50 +02:00
parent 8c8810c1b5
commit 4af11dfd30
9 changed files with 198 additions and 62 deletions

View file

@ -5,7 +5,7 @@ import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
import com.minelittlepony.unicopia.entity.behaviour.VirtualEntity; import com.minelittlepony.unicopia.entity.behaviour.Disguise;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.VecHelper; import com.minelittlepony.unicopia.util.VecHelper;
@ -55,7 +55,7 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
looked = Pony.of((PlayerEntity)looked) looked = Pony.of((PlayerEntity)looked)
.getSpellOrEmpty(DisguiseSpell.class) .getSpellOrEmpty(DisguiseSpell.class)
.map(DisguiseSpell::getDisguise) .map(DisguiseSpell::getDisguise)
.map(VirtualEntity::getAppearance) .map(Disguise::getAppearance)
.orElse(looked); .orElse(looked);
} }

View file

@ -12,7 +12,7 @@ import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.Suppressable; import com.minelittlepony.unicopia.ability.magic.Suppressable;
import com.minelittlepony.unicopia.entity.behaviour.EntityBehaviour; import com.minelittlepony.unicopia.entity.behaviour.EntityBehaviour;
import com.minelittlepony.unicopia.entity.behaviour.VirtualEntity; import com.minelittlepony.unicopia.entity.behaviour.Disguise;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
@ -26,7 +26,7 @@ import net.minecraft.nbt.CompoundTag;
public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Suppressable, FlightPredicate, HeightPredicate { public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Suppressable, FlightPredicate, HeightPredicate {
private final VirtualEntity disguise = new VirtualEntity(); private final Disguise disguise = new Disguise();
private int suppressionCounter; private int suppressionCounter;
@ -66,7 +66,7 @@ public class DisguiseSpell extends AbstractSpell implements AttachableSpell, Sup
return suppressionCounter > 0; return suppressionCounter > 0;
} }
public VirtualEntity getDisguise() { public Disguise getDisguise() {
return disguise; return disguise;
} }

View file

@ -3,12 +3,15 @@ package com.minelittlepony.unicopia.client.render;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
import com.minelittlepony.unicopia.entity.behaviour.VirtualEntity; import com.minelittlepony.unicopia.entity.behaviour.Disguise;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.model.Model; import net.minecraft.client.model.Model;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.render.entity.LivingEntityRenderer; import net.minecraft.client.render.entity.LivingEntityRenderer;
@ -49,9 +52,24 @@ public class WorldRenderDelegate {
matrices.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(roll)); matrices.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(roll));
} }
return pony.getSpellOrEmpty(DisguiseSpell.class, true) return pony.getSpellOrEmpty(DisguiseSpell.class, true).map(effect -> {
.map(effect -> renderDisguise(dispatcher, pony, effect, x, y, z, tickDelta, matrices, vertexConsumers, light)) effect.update(pony, false);
.orElse(false);
Disguise ve = effect.getDisguise();
Entity e = ve.getAppearance();
if (e != null) {
renderDisguise(dispatcher, ve, e, x, y, z, tickDelta, matrices, vertexConsumers, light);
ve.getAttachments().forEach(ee -> {
Vec3d difference = ee.getPos().subtract(e.getPos());
renderDisguise(dispatcher, ve, ee, x + difference.x, y + difference.y, z + difference.z, tickDelta, matrices, vertexConsumers, light);
});
afterEntityRender(pony, matrices);
return true;
}
return false;
}).orElse(false);
} }
public void afterEntityRender(Pony pony, MatrixStack matrices) { public void afterEntityRender(Pony pony, MatrixStack matrices) {
@ -63,15 +81,10 @@ public class WorldRenderDelegate {
} }
} }
public boolean renderDisguise(EntityRenderDispatcher dispatcher, Pony pony, DisguiseSpell effect, public void renderDisguise(EntityRenderDispatcher dispatcher, Disguise ve, Entity e,
double x, double y, double z, double x, double y, double z,
float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) { float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) {
effect.update(pony, false);
VirtualEntity ve = effect.getDisguise();
Entity e = ve.getAppearance();
if (e != null) {
if (ve.isAxisAligned() && (x != 0 || y != 0 || z != 0)) { if (ve.isAxisAligned() && (x != 0 || y != 0 || z != 0)) {
Vec3d cam = MinecraftClient.getInstance().gameRenderer.getCamera().getPos(); Vec3d cam = MinecraftClient.getInstance().gameRenderer.getCamera().getPos();
@ -80,6 +93,21 @@ public class WorldRenderDelegate {
z = MathHelper.lerp(tickDelta, e.lastRenderZ, e.getZ()) - cam.z; z = MathHelper.lerp(tickDelta, e.lastRenderZ, e.getZ()) - cam.z;
} }
BlockEntity blockEntity = ve.getBlockEntity();
if (blockEntity != null) {
blockEntity.setPos(e.getBlockPos());
matrices.push();
matrices.translate(x, y, z);
matrices.translate(-0.5, 0, -0.5);
BlockEntityRenderDispatcher.INSTANCE.get(blockEntity).render(blockEntity, 1, matrices, vertexConsumers, light, OverlayTexture.DEFAULT_UV);
matrices.pop();
return;
}
BipedEntityModel<?> model = getBipedModel(dispatcher, e); BipedEntityModel<?> model = getBipedModel(dispatcher, e);
if (model != null) { if (model != null) {
@ -91,12 +119,6 @@ public class WorldRenderDelegate {
if (model != null) { if (model != null) {
model.sneaking = false; model.sneaking = false;
} }
afterEntityRender(pony, matrices);
return true;
}
return false;
} }
@Nullable @Nullable

View file

@ -9,13 +9,14 @@ import net.minecraft.entity.passive.BeeEntity;
public class BeeBehaviour extends EntityBehaviour<BeeEntity> { public class BeeBehaviour extends EntityBehaviour<BeeEntity> {
@Override @Override
public void onCreate(BeeEntity entity) { public BeeEntity onCreate(BeeEntity entity, Disguise context) {
super.onCreate(entity); super.onCreate(entity, context);
if (entity.world.isClient) { if (entity.world.isClient) {
MinecraftClient.getInstance().getSoundManager().playNextTick( MinecraftClient.getInstance().getSoundManager().playNextTick(
entity.hasAngerTime() ? new AggressiveBeeSoundInstance(entity) : new PassiveBeeSoundInstance(entity) entity.hasAngerTime() ? new AggressiveBeeSoundInstance(entity) : new PassiveBeeSoundInstance(entity)
); );
} }
return entity;
} }
@Override @Override

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.entity.behaviour; package com.minelittlepony.unicopia.entity.behaviour;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -14,6 +16,7 @@ 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.entity.BlockEntity;
import net.minecraft.block.entity.SkullBlockEntity; import net.minecraft.block.entity.SkullBlockEntity;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
@ -30,7 +33,7 @@ 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;
public class VirtualEntity implements NbtSerialisable { public class Disguise implements NbtSerialisable {
@Nonnull @Nonnull
private String entityId = ""; private String entityId = "";
@ -38,14 +41,39 @@ public class VirtualEntity implements NbtSerialisable {
@Nullable @Nullable
private Entity entity; private Entity entity;
@Nullable
private BlockEntity blockEntity;
private List<Entity> attachments = new ArrayList<>();
@Nullable @Nullable
private CompoundTag entityNbt; private CompoundTag entityNbt;
@Nullable
private CompoundTag blockEntityNbt;
@Nullable @Nullable
public Entity getAppearance() { public Entity getAppearance() {
return entity; return entity;
} }
@Nullable
public BlockEntity getBlockEntity() {
return blockEntity;
}
public List<Entity> getAttachments() {
return attachments;
}
public void addBlockEntity(BlockEntity blockEntity) {
this.blockEntity = blockEntity;
}
public void attachExtraEntity(Entity entity) {
attachments.add(entity);
}
public void setAppearance(@Nullable Entity entity) { public void setAppearance(@Nullable Entity entity) {
remove(); remove();
@ -58,10 +86,15 @@ public class VirtualEntity implements NbtSerialisable {
} }
public void remove() { public void remove() {
attachments.clear();
if (entity != null) { if (entity != null) {
entity.remove(); entity.remove();
entity = null; entity = null;
} }
if (blockEntity != null) {
blockEntity.markRemoved();
blockEntity = null;
}
} }
private synchronized void createPlayer(CompoundTag nbt, GameProfile profile, Caster<?> source) { private synchronized void createPlayer(CompoundTag nbt, GameProfile profile, Caster<?> source) {
@ -80,6 +113,8 @@ public class VirtualEntity implements NbtSerialisable {
if (entity == null && entityNbt != null) { if (entity == null && entityNbt != null) {
CompoundTag nbt = entityNbt; CompoundTag nbt = entityNbt;
entityNbt = null; entityNbt = null;
blockEntityNbt = null;
attachments.clear();
if ("player".equals(entityId)) { if ("player".equals(entityId)) {
createPlayer(nbt, new GameProfile( createPlayer(nbt, new GameProfile(
@ -94,13 +129,11 @@ public class VirtualEntity implements NbtSerialisable {
if (source.isClient()) { if (source.isClient()) {
entity = EntityType.fromTag(nbt).map(type -> type.create(source.getWorld())).orElse(null); entity = EntityType.fromTag(nbt).map(type -> type.create(source.getWorld())).orElse(null);
if (entity != null) { if (entity != null) {
EntityBehaviour.forEntity(entity).onCreate(entity); entity = EntityBehaviour.forEntity(entity).onCreate(entity, this);
} }
} else { } else {
entity = EntityType.loadEntityWithPassengers(nbt, source.getWorld(), e -> { entity = EntityType.loadEntityWithPassengers(nbt, source.getWorld(), e -> {
EntityBehaviour.forEntity(e).onCreate(e); return EntityBehaviour.forEntity(e).onCreate(e, this);
return e;
}); });
} }
} }
@ -189,6 +222,12 @@ public class VirtualEntity implements NbtSerialisable {
} else if (entity != null) { } else if (entity != null) {
compound.put("entity", encodeEntityToNBT(entity)); compound.put("entity", encodeEntityToNBT(entity));
} }
if (blockEntityNbt != null) {
compound.put("blockEntity", blockEntityNbt);
} else if (blockEntity != null) {
compound.put("blockEntity", blockEntity.toInitialChunkDataTag());
}
} }
@Override @Override
@ -197,9 +236,14 @@ public class VirtualEntity implements NbtSerialisable {
if (!newId.contentEquals(entityId)) { if (!newId.contentEquals(entityId)) {
entityNbt = null; entityNbt = null;
blockEntityNbt = null;
remove(); remove();
} }
if (compound.contains("blockEntity")) {
blockEntityNbt = compound.getCompound("blockEntityNbt");
}
if (compound.contains("entity")) { if (compound.contains("entity")) {
entityId = newId; entityId = newId;
@ -213,6 +257,9 @@ public class VirtualEntity implements NbtSerialisable {
} catch (Exception ignored) { } catch (Exception ignored) {
// Mojang pls // Mojang pls
} }
attachments.clear();
entity = EntityBehaviour.forEntity(entity).onCreate(entity, this);
} }
} }
} }

View file

@ -17,6 +17,7 @@ import net.minecraft.entity.passive.TameableEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
public class EntityBehaviour<T extends Entity> { public class EntityBehaviour<T extends Entity> {
@ -28,20 +29,25 @@ public class EntityBehaviour<T extends Entity> {
} }
public void onCreate(T entity) { public T onCreate(T entity, Disguise context) {
entity.extinguish(); entity.extinguish();
return entity;
} }
public void copyBaseAttributes(LivingEntity from, Entity to) { public void copyBaseAttributes(LivingEntity from, Entity to) {
copyBaseAttributes(from, to, Vec3d.ZERO);
}
public void copyBaseAttributes(LivingEntity from, Entity to, Vec3d positionOffset) {
// Set first because position calculations rely on it // Set first because position calculations rely on it
to.age = from.age; to.age = from.age;
to.removed = from.removed; to.removed = from.removed;
to.setOnGround(from.isOnGround()); to.setOnGround(from.isOnGround());
if (VirtualEntity.isAxisAligned(to)) { if (Disguise.isAxisAligned(to)) {
double x = Math.floor(from.getX()) + 0.5; double x = positionOffset.x + Math.floor(from.getX()) + 0.5;
double y = Math.floor(from.getY()); double y = positionOffset.y + Math.floor(from.getY());
double z = Math.floor(from.getZ()) + 0.5; double z = positionOffset.z + Math.floor(from.getZ()) + 0.5;
to.prevX = x; to.prevX = x;
to.prevY = y; to.prevY = y;
@ -59,25 +65,25 @@ public class EntityBehaviour<T extends Entity> {
} else { } else {
to.copyPositionAndRotation(from); to.copyPositionAndRotation(from);
to.prevX = from.prevX; to.prevX = positionOffset.x + from.prevX;
to.prevY = from.prevY; to.prevY = positionOffset.y + from.prevY;
to.prevZ = from.prevZ; to.prevZ = positionOffset.z + from.prevZ;
to.chunkX = from.chunkX; to.chunkX = from.chunkX;
to.chunkY = from.chunkY; to.chunkY = from.chunkY;
to.chunkZ = from.chunkZ; to.chunkZ = from.chunkZ;
to.lastRenderX = from.lastRenderX; to.lastRenderX = positionOffset.x + from.lastRenderX;
to.lastRenderY = from.lastRenderY; to.lastRenderY = positionOffset.y + from.lastRenderY;
to.lastRenderZ = from.lastRenderZ; to.lastRenderZ = positionOffset.z + from.lastRenderZ;
} }
if (to instanceof PlayerEntity) { if (to instanceof PlayerEntity) {
PlayerEntity l = (PlayerEntity)to; PlayerEntity l = (PlayerEntity)to;
l.capeX = l.getX(); l.capeX = positionOffset.x + l.getX();
l.capeY = l.getY(); l.capeY = positionOffset.y + l.getY();
l.capeZ = l.getZ(); l.capeZ = positionOffset.z + l.getZ();
} }
to.setVelocity(from.getVelocity()); to.setVelocity(from.getVelocity());
@ -174,6 +180,7 @@ public class EntityBehaviour<T extends Entity> {
} }
static { static {
register(FallingBlockBehaviour::new, EntityType.FALLING_BLOCK);
register(VillagerBehaviour::new, EntityType.VILLAGER, EntityType.WANDERING_TRADER); register(VillagerBehaviour::new, EntityType.VILLAGER, EntityType.WANDERING_TRADER);
register(SheepBehaviour::new, EntityType.SHEEP); register(SheepBehaviour::new, EntityType.SHEEP);
register(BeeBehaviour::new, EntityType.BEE); register(BeeBehaviour::new, EntityType.BEE);

View file

@ -0,0 +1,58 @@
package com.minelittlepony.unicopia.entity.behaviour;
import java.util.List;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.DoorBlock;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.entity.Entity;
import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.tag.BlockTags;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
public class FallingBlockBehaviour extends EntityBehaviour<FallingBlockEntity> {
private static final Vec3d UP = Vec3d.of(Direction.UP.getVector());
@Override
public FallingBlockEntity onCreate(FallingBlockEntity entity, Disguise context) {
super.onCreate(entity, context);
BlockState state = entity.getBlockState();
Block block = state.getBlock();
if (block == Blocks.SAND) {
block = Blocks.BLACKSTONE;
}
if (state.isIn(BlockTags.DOORS) && block instanceof DoorBlock) {
BlockState lowerState = state.with(DoorBlock.HALF, DoubleBlockHalf.LOWER);
BlockState upperState = state.with(DoorBlock.HALF, DoubleBlockHalf.UPPER);
context.attachExtraEntity(new FallingBlockEntity(entity.world, entity.getX(), entity.getY(), entity.getZ(), upperState));
return new FallingBlockEntity(entity.world, entity.getX(), entity.getY() + 1, entity.getZ(), lowerState);
}
if (block instanceof BlockEntityProvider) {
context.addBlockEntity(((BlockEntityProvider)block).createBlockEntity(entity.world));
}
return entity;
}
@Override
public void update(Caster<?> source, FallingBlockEntity entity, Spell spell) {
List<Entity> attachments = ((DisguiseSpell)spell).getDisguise().getAttachments();
if (attachments.size() > 0) {
copyBaseAttributes(source.getOwner(), attachments.get(0), UP);
}
}
}

View file

@ -11,11 +11,12 @@ import net.minecraft.entity.vehicle.AbstractMinecartEntity;
public class MinecartBehaviour extends EntityBehaviour<AbstractMinecartEntity> { public class MinecartBehaviour extends EntityBehaviour<AbstractMinecartEntity> {
@Override @Override
public void onCreate(AbstractMinecartEntity entity) { public AbstractMinecartEntity onCreate(AbstractMinecartEntity entity, Disguise context) {
super.onCreate(entity); super.onCreate(entity, context);
if (entity.world.isClient) { if (entity.world.isClient) {
MinecraftClient.getInstance().getSoundManager().play(new MovingMinecartSoundInstance(entity)); MinecraftClient.getInstance().getSoundManager().play(new MovingMinecartSoundInstance(entity));
} }
return entity;
} }
@Override @Override

View file

@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
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;
import com.minelittlepony.unicopia.entity.behaviour.VirtualEntity; import com.minelittlepony.unicopia.entity.behaviour.Disguise;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.Equine;
@ -51,7 +51,7 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
if (get() instanceof Pony && horizontalCollision) { if (get() instanceof Pony && horizontalCollision) {
((Pony)get()).getSpellOrEmpty(DisguiseSpell.class, false) ((Pony)get()).getSpellOrEmpty(DisguiseSpell.class, false)
.map(DisguiseSpell::getDisguise) .map(DisguiseSpell::getDisguise)
.filter(VirtualEntity::canClimbWalls) .filter(Disguise::canClimbWalls)
.ifPresent(v -> { .ifPresent(v -> {
climbingPos = Optional.of(getBlockPos()); climbingPos = Optional.of(getBlockPos());
info.setReturnValue(true); info.setReturnValue(true);