diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java index faa7df4f..2b6a7b9a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/MindSwapSpell.java @@ -9,6 +9,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell; import com.minelittlepony.unicopia.ability.magic.spell.Situation; import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.entity.EntityReference; +import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.behaviour.EntitySwap; import com.minelittlepony.unicopia.entity.behaviour.Inventory; import com.minelittlepony.unicopia.projectile.MagicProjectileEntity; @@ -18,7 +19,9 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.world.GameMode; public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.EntityHitListener { @@ -43,21 +46,27 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti super.onDestroyed(caster); if (initialized && !caster.isClient()) { counterpart.ifPresent(caster.asWorld(), e -> { + initialized = false; LivingEntity master = caster.getMaster(); - EntitySwap.ALL.accept(e, master); - Inventory.swapInventories( - e, myStoredInventory.or(() -> Inventory.of(e)), - master, theirStoredInventory.or(() -> Inventory.of(master)), - a -> {}, - a -> {} - ); - Caster other = Caster.of(e).get(); other.getSpellSlot().removeIf(SpellType.MIMIC, true); + caster.getSpellSlot().removeIf(getType(), true); - other.playSound(USounds.SPELL_MINDSWAP_UNSWAP, 1); - caster.playSound(USounds.SPELL_MINDSWAP_UNSWAP, 1); + if (master instanceof ServerPlayerEntity sMaster && e instanceof ServerPlayerEntity sE) { + swapPlayerData(sMaster, sE); + } else { + EntitySwap.ALL.accept(e, master); + Inventory.swapInventories( + e, myStoredInventory.or(() -> Inventory.of(e)), + master, theirStoredInventory.or(() -> Inventory.of(master)), + a -> {}, + a -> {} + ); + } + + other.playSound(USounds.SPELL_MINDSWAP_UNSWAP, 0.2F); + caster.playSound(USounds.SPELL_MINDSWAP_UNSWAP, 0.2F); }); counterpart.set(null); } @@ -72,8 +81,6 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti if (!caster.isClient()) { if (!initialized) { - initialized = true; - setDirty(); counterpart.ifPresent(caster.asWorld(), e -> { LivingEntity master = caster.getMaster(); @@ -81,23 +88,39 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti Caster other = Caster.of(e).get(); SpellType.MIMIC.withTraits().apply(other, CastingMethod.INDIRECT).setDisguise(master); - EntitySwap.ALL.accept(master, e); - Inventory.swapInventories( - master, Inventory.of(master), - e, Inventory.of(e), - a -> myStoredInventory = Optional.of(a), - a -> theirStoredInventory = Optional.of(a) - ); + if (master instanceof ServerPlayerEntity sMaster && e instanceof ServerPlayerEntity sE) { + swapPlayerData(sMaster, sE); + } else { + EntitySwap.ALL.accept(master, e); + Inventory.swapInventories( + master, Inventory.of(master), + e, Inventory.of(e), + a -> myStoredInventory = Optional.of(a), + a -> theirStoredInventory = Optional.of(a) + ); + } other.playSound(USounds.SPELL_MINDSWAP_SWAP, 1); caster.playSound(USounds.SPELL_MINDSWAP_SWAP, 1); }); + initialized = true; + setDirty(); } - if (counterpart.isSet() && counterpart.get(caster.asWorld()) == null) { - caster.getOriginatingCaster().asEntity().damage(caster.asWorld().getDamageSources().magic(), Float.MAX_VALUE); - setDead(); - return false; + if (counterpart.isSet()) { + LivingEntity other = counterpart.get(caster.asWorld()); + + if (other == null) { + caster.getOriginatingCaster().asEntity().damage(caster.asWorld().getDamageSources().magic(), Float.MAX_VALUE); + setDead(); + return false; + } + + if (!Caster.of(other).get().getSpellSlot().contains(SpellType.MIMIC)) { + onDestroyed(caster); + setDead(); + return false; + } } if (!caster.asEntity().isAlive()) { @@ -149,6 +172,48 @@ public class MindSwapSpell extends MimicSpell implements ProjectileDelegate.Enti myStoredInventory = Optional.ofNullable(compound.contains("myStoredInventory", NbtElement.COMPOUND_TYPE) ? Inventory.fromNBT(compound.getCompound("myStoredInventory")) : null); theirStoredInventory = Optional.ofNullable(compound.contains("theirStoredInventory", NbtElement.COMPOUND_TYPE) ? Inventory.fromNBT(compound.getCompound("theirStoredInventory")) : null); } + + private static void swapPlayerData(ServerPlayerEntity a, ServerPlayerEntity b) { + + final GameMode aMode = a.interactionManager.getGameMode(); + final GameMode bMode = b.interactionManager.getGameMode(); + + final ServerPlayerEntity aClone = clonePlayer(a); + final ServerPlayerEntity bClone = clonePlayer(b); + + aClone.getAbilities().creativeMode = a.getAbilities().creativeMode; + bClone.getAbilities().creativeMode = b.getAbilities().creativeMode; + + a.copyFrom(bClone, true); + b.copyFrom(aClone, true); + + a.interactionManager.changeGameMode(aMode); + b.interactionManager.changeGameMode(bMode); + + a.deathTime = 0; + b.deathTime = 0; + + EntitySwap.POSITION.accept(a, b); + EntitySwap.VELOCITY.accept(a, b); + EntitySwap.PITCH.accept(a, b); + EntitySwap.YAW.accept(a, b); + + a.sendAbilitiesUpdate(); + b.sendAbilitiesUpdate(); + + Living.updateVelocity(a); + Living.updateVelocity(b); + } + + private static ServerPlayerEntity clonePlayer(ServerPlayerEntity player) { + ServerPlayerEntity clone = new ServerPlayerEntity(player.getServer(), player.getServerWorld(), player.getGameProfile()); + + NbtCompound compound = player.writeNbt(new NbtCompound()); + compound.remove("Dimension"); + compound.getCompound("unicopia_caster").remove("spells"); + clone.readNbt(compound); + return clone; + } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 779d4e61..cffb733d 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -862,7 +862,6 @@ public class Pony extends Living implements Copyable, Update } } - oldPlayer.getSpellSlot().put(null); setSpecies(oldPlayer.respawnRace != Race.UNSET && !alive ? oldPlayer.respawnRace : oldPlayer.getActualSpecies()); getDiscoveries().copyFrom(oldPlayer.getDiscoveries(), alive); getPhysics().copyFrom(oldPlayer.getPhysics(), alive);