diff --git a/src/main/java/com/minelittlepony/unicopia/InteractionManager.java b/src/main/java/com/minelittlepony/unicopia/InteractionManager.java index 20a319a8..e891f2a0 100644 --- a/src/main/java/com/minelittlepony/unicopia/InteractionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/InteractionManager.java @@ -7,10 +7,12 @@ import com.minelittlepony.unicopia.entity.player.dummy.DummyPlayerEntity; import com.minelittlepony.unicopia.entity.player.dummy.DummyServerPlayerEntity; import com.minelittlepony.unicopia.network.handler.ClientNetworkHandler; import com.mojang.authlib.GameProfile; +import com.mojang.authlib.minecraft.MinecraftSessionService; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.World; public class InteractionManager { public static final int SOUND_EARS_RINGING = 0; @@ -24,6 +26,14 @@ public class InteractionManager { return INSTANCE; } + public MinecraftSessionService getSessionService(World world) { + if (world instanceof ServerWorld) { + return ((ServerWorld)world).getServer().getSessionService(); + } + + throw new NullPointerException("Cannot get session service"); + } + /** * Returns the client network handler, or throws if called on the server. */ @@ -60,9 +70,19 @@ public class InteractionManager { */ @NotNull public PlayerEntity createPlayer(Entity observer, GameProfile profile) { - if (observer.world instanceof ServerWorld) { - return new DummyServerPlayerEntity((ServerWorld)observer.world, profile); + return createPlayer(observer.world, profile); + } + + /** + * Side-independent method to create a new player. + * + * Returns an implementation of PlayerEntity appropriate to the side being called on. + */ + @NotNull + public PlayerEntity createPlayer(World world, GameProfile profile) { + if (world instanceof ServerWorld) { + return new DummyServerPlayerEntity((ServerWorld)world, profile); } - return new DummyPlayerEntity(observer.world, profile); + return new DummyPlayerEntity(world, profile); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java index 4bb86bdb..8c7ccea4 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java @@ -14,6 +14,7 @@ import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity; import com.minelittlepony.unicopia.network.handler.ClientNetworkHandler; import com.minelittlepony.unicopia.network.handler.ClientNetworkHandlerImpl; import com.mojang.authlib.GameProfile; +import com.mojang.authlib.minecraft.MinecraftSessionService; import net.minecraft.client.MinecraftClient; import net.minecraft.client.sound.AggressiveBeeSoundInstance; @@ -26,12 +27,18 @@ import net.minecraft.entity.LivingEntity; import net.minecraft.entity.passive.BeeEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.vehicle.AbstractMinecartEntity; +import net.minecraft.world.World; public class ClientInteractionManager extends InteractionManager { private final ClientNetworkHandler handler = new ClientNetworkHandlerImpl(); private final MinecraftClient client = MinecraftClient.getInstance(); + @Override + public MinecraftSessionService getSessionService(World world) { + return MinecraftClient.getInstance().getSessionService(); + } + @Override @Nullable public ClientNetworkHandler getClientNetworkHandler() { @@ -62,11 +69,11 @@ public class ClientInteractionManager extends InteractionManager { @Override @NotNull - public PlayerEntity createPlayer(Entity observer, GameProfile profile) { - if (observer.world instanceof ClientWorld) { - return new DummyClientPlayerEntity((ClientWorld)observer.world, profile); + public PlayerEntity createPlayer(World world, GameProfile profile) { + if (world instanceof ClientWorld) { + return new DummyClientPlayerEntity((ClientWorld)world, profile); } - return super.createPlayer(observer, profile); + return super.createPlayer(world, profile); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/entity/CapeHolder.java b/src/main/java/com/minelittlepony/unicopia/entity/CapeHolder.java new file mode 100644 index 00000000..23bd3500 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/CapeHolder.java @@ -0,0 +1,5 @@ +package com.minelittlepony.unicopia.entity; + +public interface CapeHolder { + void callUpdateCapeAngles(); +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Leaner.java b/src/main/java/com/minelittlepony/unicopia/entity/Leaner.java index e09ca7f3..89bbf51a 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Leaner.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Leaner.java @@ -4,4 +4,13 @@ public interface Leaner { float getLeaningPitch(); void setLeaningPitch(float pitch); + + float getLastLeaningPitch(); + + void setLastLeaningPitch(float pitch); + + default void copyFrom(Leaner other) { + setLeaningPitch(other.getLeaningPitch()); + setLastLeaningPitch(other.getLastLeaningPitch()); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java index e0fd8c3d..3ed0eb6b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/Disguise.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.entity.behaviour; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.UUID; import java.util.function.Consumer; @@ -144,16 +145,20 @@ public class Disguise implements NbtSerialisable { public Entity getOrCreate(Caster source) { if (entity == null && entityNbt != null) { NbtCompound nbt = entityNbt; + entity = null; entityNbt = null; attachments.clear(); if ("player".equals(entityId)) { createPlayer(nbt, new GameProfile( - nbt.getUuid("playerId"), - nbt.getString("playerName") - ), source); + nbt.containsUuid("playerId") ? nbt.getUuid("playerId") : UUID.randomUUID(), + nbt.getString("playerName") + ), source); - SkullBlockEntity.loadProperties(new GameProfile(null, nbt.getString("playerName")), profile ->{ }); + SkullBlockEntity.loadProperties(new GameProfile( + nbt.containsUuid("playerId") ? nbt.getUuid("playerId") : null, + nbt.getString("playerName") + ), p -> createPlayer(nbt, p, source)); } else { if (source.isClient()) { entity = EntityType.fromNbt(nbt).map(type -> type.create(source.getWorld())).orElse(null); @@ -170,9 +175,9 @@ public class Disguise implements NbtSerialisable { return EntityBehaviour.forEntity(e).onCreate(e, this, true); }); } - } - onEntityLoaded(source); + onEntityLoaded(source); + } } return entity; @@ -282,7 +287,14 @@ public class Disguise implements NbtSerialisable { public void fromNBT(NbtCompound compound) { String newId = compound.getString("entityId"); - if (!newId.contentEquals(entityId)) { + String newPlayerName = null; + if (compound.contains("entity") && compound.getCompound("entity").contains("playerName")) { + newPlayerName = compound.getCompound("entity").getString("playerName"); + } + + String oldPlayerName = entity != null && entity instanceof PlayerEntity ? ((PlayerEntity)entity).getGameProfile().getName() : null; + + if (!Objects.equals(newId, entityId) || !Objects.equals(newPlayerName, oldPlayerName)) { entityNbt = null; remove(); } @@ -320,7 +332,9 @@ public class Disguise implements NbtSerialisable { GameProfile profile = ((PlayerEntity)entity).getGameProfile(); entityNbt.putString("id", "player"); - entityNbt.putUuid("playerId", profile.getId()); + if (profile.getId() != null) { + entityNbt.putUuid("playerId", profile.getId()); + } entityNbt.putString("playerName", profile.getName()); NbtCompound tag = new NbtCompound(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java index 90ff0a54..3536bc5e 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/EntityBehaviour.java @@ -40,6 +40,11 @@ public class EntityBehaviour { private static final EntityBehaviour DEFAULT = new EntityBehaviour<>(); private static final Registry> REGISTRY = Registries.createSimple(new Identifier("unicopia", "entity_behaviour")); + /** + * Equivalent of the entity#tick method. Called every tick to update th logic for a disguise. + *
+ * We use this to add entity-specific behaviours. + */ public void update(Caster source, T entity, DisguiseSpell spell) { if (source instanceof Pony) { update((Pony)source, entity, spell); @@ -151,14 +156,6 @@ public class EntityBehaviour { to.lastRenderZ = positionOffset.z + from.lastRenderZ; } - if (to instanceof PlayerEntity) { - PlayerEntity l = (PlayerEntity)to; - - l.capeX = positionOffset.x + l.getX(); - l.capeY = positionOffset.y + l.getY(); - l.capeZ = positionOffset.z + l.getZ(); - } - to.setVelocity(from.getVelocity()); to.setPitch(from.getPitch()); @@ -267,6 +264,7 @@ public class EntityBehaviour { } static { + register(PlayerBehaviour::new, EntityType.PLAYER); register(FallingBlockBehaviour::new, EntityType.FALLING_BLOCK); register(MobBehaviour::new, EntityType.RAVAGER, EntityType.IRON_GOLEM); register(HoppingBehaviour::new, EntityType.RABBIT, EntityType.SLIME, EntityType.MAGMA_CUBE); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/behaviour/PlayerBehaviour.java b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/PlayerBehaviour.java new file mode 100644 index 00000000..964cdf79 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/behaviour/PlayerBehaviour.java @@ -0,0 +1,37 @@ +package com.minelittlepony.unicopia.entity.behaviour; + +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; +import com.minelittlepony.unicopia.entity.CapeHolder; +import com.minelittlepony.unicopia.entity.Leaner; +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.entity.player.PlayerEntity; + +public class PlayerBehaviour extends EntityBehaviour { + @Override + public void update(Caster source, PlayerEntity entity, DisguiseSpell spell) { + if (source instanceof Pony) { + PlayerEntity pFrom = ((Pony)source).getMaster(); + + entity.capeX = pFrom.capeX; + entity.capeY = pFrom.capeY; + entity.capeZ = pFrom.capeZ; + entity.prevCapeX = pFrom.prevCapeX; + entity.prevCapeY = pFrom.prevCapeY; + entity.prevCapeZ = pFrom.prevCapeZ; + } else { + ((CapeHolder)entity).callUpdateCapeAngles(); + } + + if (source.getEntity().getPose() != entity.getPose()) { + entity.setPose(source.getEntity().getPose()); + } + if (source.getEntity().isSwimming() != entity.isSwimming()) { + entity.setSwimming(source.getEntity().isSwimming()); + } + if (source.getEntity() instanceof Leaner) { + ((Leaner)entity).copyFrom(((Leaner)source.getEntity())); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/dummy/DummyServerPlayerEntity.java b/src/main/java/com/minelittlepony/unicopia/entity/player/dummy/DummyServerPlayerEntity.java index a6b82c88..c6af0120 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/dummy/DummyServerPlayerEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/dummy/DummyServerPlayerEntity.java @@ -4,6 +4,7 @@ import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.Owned; import com.mojang.authlib.GameProfile; +import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; @@ -22,6 +23,11 @@ public class DummyServerPlayerEntity extends ServerPlayerEntity implements Owned /*noop*/ } + @Override + protected void onBlockCollision(BlockState state) { + /*noop*/ + } + @Override public PlayerEntity getMaster() { return owner; diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java index dad579bd..afe833fa 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java @@ -75,6 +75,14 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer info) { Creature.registerAttributes(info.getReturnValue()); diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java index 847e03b9..f9547f98 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinPlayerEntity.java @@ -1,11 +1,13 @@ package com.minelittlepony.unicopia.mixin; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; 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.entity.PonyContainer; +import com.minelittlepony.unicopia.entity.CapeHolder; import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.player.Pony; import com.mojang.datafixers.util.Either; @@ -25,8 +27,11 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @Mixin(PlayerEntity.class) -abstract class MixinPlayerEntity extends LivingEntity implements PonyContainer { +abstract class MixinPlayerEntity extends LivingEntity implements PonyContainer, CapeHolder { private MixinPlayerEntity() { super(null, null); } + @Override + @Invoker("updateCapeAngles") + public abstract void callUpdateCapeAngles(); @Override public Equine create() {