Fixed data not being copied when the player changes dimensions

This commit is contained in:
Sollace 2024-05-25 21:01:01 +01:00
parent 6057d8ea3b
commit e9114f9e12
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
10 changed files with 101 additions and 20 deletions

View file

@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellReference; import com.minelittlepony.unicopia.ability.magic.spell.SpellReference;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.network.track.ObjectTracker; import com.minelittlepony.unicopia.network.track.ObjectTracker;
import com.minelittlepony.unicopia.network.track.Trackable; import com.minelittlepony.unicopia.network.track.Trackable;
import com.minelittlepony.unicopia.network.track.TrackableObject; import com.minelittlepony.unicopia.network.track.TrackableObject;
@ -128,4 +129,13 @@ class MultiSpellSlot implements SpellSlots, NbtSerialisable {
spell.fromNBT(compound); spell.fromNBT(compound);
} }
} }
@Override
public void copyFrom(SpellSlots other, boolean alive) {
if (alive) {
other.stream().forEach(this::put);
} else {
other.stream().filter(SpellType.PLACE_CONTROL_SPELL).forEach(this::put);
}
}
} }

View file

@ -65,4 +65,9 @@ class SingleSpellSlot implements SpellSlots, NbtSerialisable {
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
entry.readTrackedNbt(compound.getCompound("effect")); entry.readTrackedNbt(compound.getCompound("effect"));
} }
@Override
public void copyFrom(SpellSlots other, boolean alive) {
other.get().ifPresent(this::put);
}
} }

View file

@ -7,9 +7,10 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.ability.magic.spell.Spell; import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.util.Copyable;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
public interface SpellSlots extends NbtSerialisable { public interface SpellSlots extends NbtSerialisable, Copyable<SpellSlots> {
static SpellInventory ofUnbounded(Caster<?> caster) { static SpellInventory ofUnbounded(Caster<?> caster) {
return new SpellInventory(caster, new MultiSpellSlot(caster)); return new SpellInventory(caster, new MultiSpellSlot(caster));
} }

View file

@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
import com.minelittlepony.unicopia.item.EnchantableItem; import com.minelittlepony.unicopia.item.EnchantableItem;
import com.minelittlepony.unicopia.util.Copyable;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
@ -15,7 +16,7 @@ import net.minecraft.nbt.NbtList;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult; import net.minecraft.util.TypedActionResult;
public class PlayerCharmTracker implements NbtSerialisable { public class PlayerCharmTracker implements NbtSerialisable, Copyable<PlayerCharmTracker> {
private final Pony pony; private final Pony pony;
@ -62,6 +63,13 @@ public class PlayerCharmTracker implements NbtSerialisable {
return previous; return previous;
} }
@Override
public void copyFrom(PlayerCharmTracker old, boolean alive) {
for (int i = 0; i < handSpells.length; i++) {
handSpells[i] = old.handSpells[i];
}
}
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
NbtList equippedSpells = new NbtList(); NbtList equippedSpells = new NbtList();

View file

@ -63,7 +63,6 @@ import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.*; import net.minecraft.util.math.*;
import net.minecraft.world.GameMode; import net.minecraft.world.GameMode;
import net.minecraft.world.GameRules; import net.minecraft.world.GameRules;
@ -116,6 +115,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
sender.accept(Channel.SERVER_PLAYER_CAPABILITIES.toPacket(new MsgPlayerCapabilities(this))); sender.accept(Channel.SERVER_PLAYER_CAPABILITIES.toPacket(new MsgPlayerCapabilities(this)));
} }
}); });
race = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.UNSET); race = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.UNSET);
suppressedRace = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.UNSET); suppressedRace = this.tracker.startTracking(Race.TRACKABLE_TYPE, Race.UNSET);
this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP);
@ -817,8 +817,6 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override @Override
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString());
compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString());
compound.put("mana", mana.toNBT()); compound.put("mana", mana.toNBT());
compound.putInt("levels", levels.get()); compound.putInt("levels", levels.get());
compound.putInt("corruption", corruption.get()); compound.putInt("corruption", corruption.get());
@ -827,8 +825,6 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override @Override
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN));
setSuppressedRace(Race.fromName(compound.getString("suppressedSpecies"), Race.UNSET));
levels.set(compound.getInt("levels")); levels.set(compound.getInt("levels"));
corruption.set(compound.getInt("corruption")); corruption.set(compound.getInt("corruption"));
mana.fromNBT(compound.getCompound("mana")); mana.fromNBT(compound.getCompound("mana"));
@ -837,7 +833,10 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override @Override
public void toSyncronisedNbt(NbtCompound compound) { public void toSyncronisedNbt(NbtCompound compound) {
System.out.println("toSyncNbt");
super.toSyncronisedNbt(compound); super.toSyncronisedNbt(compound);
compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString());
compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString());
compound.putFloat("magicExhaustion", magicExhaustion); compound.putFloat("magicExhaustion", magicExhaustion);
compound.putInt("ticksInSun", ticksInSun); compound.putInt("ticksInSun", ticksInSun);
compound.putBoolean("hasShades", hasShades); compound.putBoolean("hasShades", hasShades);
@ -857,7 +856,10 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override @Override
public void fromSynchronizedNbt(NbtCompound compound) { public void fromSynchronizedNbt(NbtCompound compound) {
System.out.println("fromSyncNbt");
super.fromSynchronizedNbt(compound); super.fromSynchronizedNbt(compound);
setSpecies(Race.fromName(compound.getString("playerSpecies"), Race.HUMAN));
setSuppressedRace(Race.fromName(compound.getString("suppressedSpecies"), Race.UNSET));
powers.fromNBT(compound.getCompound("powers")); powers.fromNBT(compound.getCompound("powers"));
gravity.fromNBT(compound.getCompound("gravity")); gravity.fromNBT(compound.getCompound("gravity"));
charms.fromNBT(compound.getCompound("charms")); charms.fromNBT(compound.getCompound("charms"));
@ -877,7 +879,6 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override @Override
public void copyFrom(Pony oldPlayer, boolean alive) { public void copyFrom(Pony oldPlayer, boolean alive) {
boolean forcedSwap = (!alive boolean forcedSwap = (!alive
&& entity instanceof ServerPlayerEntity && entity instanceof ServerPlayerEntity
&& entity.getWorld().getGameRules().getBoolean(UGameRules.SWAP_TRIBE_ON_DEATH) && entity.getWorld().getGameRules().getBoolean(UGameRules.SWAP_TRIBE_ON_DEATH)
@ -885,17 +886,20 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|| oldPlayer.getSpecies().isUnset(); || oldPlayer.getSpecies().isUnset();
Race oldSuppressedRace = oldPlayer.getSuppressedRace(); Race oldSuppressedRace = oldPlayer.getSuppressedRace();
Race newRace = oldPlayer.respawnRace != Race.UNSET && !alive ? oldPlayer.respawnRace : oldPlayer.getSpecies();
if (alive) { if (forcedSwap || !newRace.canCast()) {
oldPlayer.getSpellSlot().stream().forEach(getSpellSlot()::put); getSpellSlot().clear();
} else { } else {
if (forcedSwap) { getSpellSlot().copyFrom(oldPlayer.getSpellSlot(), alive);
oldSuppressedRace = Race.UNSET; }
Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(entity), "gui.unicopia.tribe_selection.respawn"), (ServerPlayerEntity)entity);
} else {
oldPlayer.getSpellSlot().stream().filter(SpellType.PLACE_CONTROL_SPELL).forEach(getSpellSlot()::put);
}
if (forcedSwap) {
oldSuppressedRace = Race.UNSET;
Channel.SERVER_SELECT_TRIBE.sendToPlayer(new MsgTribeSelect(Race.allPermitted(entity), "gui.unicopia.tribe_selection.respawn"), (ServerPlayerEntity)entity);
}
if (!alive) {
// putting it here instead of adding another injection point into ServerPlayerEntity.copyFrom() // putting it here instead of adding another injection point into ServerPlayerEntity.copyFrom()
if (!asWorld().getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) { if (!asWorld().getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) {
PlayerInventory inventory = oldPlayer.asEntity().getInventory(); PlayerInventory inventory = oldPlayer.asEntity().getInventory();
@ -908,14 +912,13 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
} }
} }
setSpecies(oldPlayer.respawnRace != Race.UNSET && !alive ? oldPlayer.respawnRace : oldPlayer.getSpecies()); setSpecies(newRace);
setSuppressedRace(oldSuppressedRace); setSuppressedRace(oldSuppressedRace);
getDiscoveries().copyFrom(oldPlayer.getDiscoveries(), alive); getDiscoveries().copyFrom(oldPlayer.getDiscoveries(), alive);
getPhysics().copyFrom(oldPlayer.getPhysics(), alive); getPhysics().copyFrom(oldPlayer.getPhysics(), alive);
if (!forcedSwap) { if (!forcedSwap) {
getArmour().copyFrom(oldPlayer.getArmour(), alive); getArmour().copyFrom(oldPlayer.getArmour(), alive);
getCharms().equipSpell(Hand.MAIN_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.MAIN_HAND)); getCharms().copyFrom(oldPlayer.getCharms(), alive);
getCharms().equipSpell(Hand.OFF_HAND, oldPlayer.getCharms().getEquippedSpell(Hand.OFF_HAND));
corruption.set(oldPlayer.getCorruption().get()); corruption.set(oldPlayer.getCorruption().get());
levels.set(oldPlayer.getLevel().get()); levels.set(oldPlayer.getLevel().get());
} }

View file

@ -1,5 +1,7 @@
package com.minelittlepony.unicopia.mixin.client; package com.minelittlepony.unicopia.mixin.client;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@ -10,13 +12,19 @@ import com.minelittlepony.unicopia.ability.magic.SpellPredicate;
import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.behaviour.Disguise; import com.minelittlepony.unicopia.entity.behaviour.Disguise;
import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance; import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.track.Trackable;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket;
import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket;
@Mixin(ClientPlayNetworkHandler.class) @Mixin(ClientPlayNetworkHandler.class)
abstract class MixinClientPlayNetworkHandler { abstract class MixinClientPlayNetworkHandler {
@Shadow private @Final MinecraftClient client;
@Shadow private ClientWorld world; @Shadow private ClientWorld world;
@Inject(method = "onEntityStatus", at = @At("TAIL")) @Inject(method = "onEntityStatus", at = @At("TAIL"))
@ -32,4 +40,20 @@ abstract class MixinClientPlayNetworkHandler {
}); });
} }
} }
@Nullable
private ClientPlayerEntity oldPlayer;
@Inject(method = "onPlayerRespawn", at = @At("HEAD"))
public void beforeOnPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo info) {
oldPlayer = client.player;
}
@Inject(method = "onPlayerRespawn", at = @At("RETURN"))
public void afterOnPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo info) {
if (oldPlayer != null && oldPlayer != client.player) {
Trackable.of(oldPlayer).getDataTrackers().copyTo(Trackable.of(client.player).getDataTrackers());
Pony.of(client.player).copyFrom(Pony.of(oldPlayer), true);
}
}
} }

View file

@ -43,7 +43,7 @@ abstract class MixinServerPlayNetworkHandler implements EntityTrackingListener,
} }
@Inject(method = "tick()V", at = @At("HEAD")) @Inject(method = "tick()V", at = @At("HEAD"))
private void beforePlayerTick() { private void beforePlayerTick(CallbackInfo info) {
if (Pony.of(player).getPhysics().isFlyingSurvival) { if (Pony.of(player).getPhysics().isFlyingSurvival) {
floating = false; floating = false;
floatingTicks = 0; floatingTicks = 0;

View file

@ -75,6 +75,17 @@ public class DataTracker {
} }
} }
@SuppressWarnings("unchecked")
synchronized void copyTo(DataTracker destination) {
for (int i = 0; i < codecs.size(); i++) {
((Pair<Object>)destination.codecs.get(i)).value = codecs.get(i).value;
TrackableObject o = destination.persistentObjects.get(i);
if (o != null) {
o.readTrackedNbt((NbtCompound)codecs.get(i).value);
}
}
}
synchronized Optional<MsgTrackedValues.TrackerEntries> getInitialPairs() { synchronized Optional<MsgTrackedValues.TrackerEntries> getInitialPairs() {
initial = false; initial = false;
dirtyIndices = new IntOpenHashSet(); dirtyIndices = new IntOpenHashSet();

View file

@ -80,6 +80,16 @@ public class DataTrackerManager {
} }
} }
@SuppressWarnings({ "unchecked", "rawtypes" })
public synchronized void copyTo(DataTrackerManager destination) {
for (int i = 0; i < trackers.size(); i++) {
trackers.get(i).copyTo(i >= destination.trackers.size() ? destination.checkoutTracker() : destination.trackers.get(i));
}
for (int i = 0; i < objectTrackers.size(); i++) {
((ObjectTracker)objectTrackers.get(i)).copyTo(destination.objectTrackers.get(i));
}
}
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
public synchronized void sendInitial(ServerPlayerEntity player, Consumer<Packet<ClientPlayPacketListener>> sender) { public synchronized void sendInitial(ServerPlayerEntity player, Consumer<Packet<ClientPlayPacketListener>> sender) {
synchronized (this) { synchronized (this) {

View file

@ -73,6 +73,15 @@ public class ObjectTracker<T extends TrackableObject> implements NbtSerialisable
quickAccess = Map.copyOf(trackedObjects); quickAccess = Map.copyOf(trackedObjects);
} }
synchronized void copyTo(ObjectTracker<T> destination) {
for (var entry : trackedObjects.entrySet()) {
T copy = destination.constructor.get();
copy.readTrackedNbt(entry.getValue().toTrackedNbt());
destination.trackedObjects.put(entry.getKey(), copy);
}
destination.quickAccess = Map.copyOf(destination.trackedObjects);
}
synchronized Optional<MsgTrackedValues.TrackerObjects> getInitialPairs() { synchronized Optional<MsgTrackedValues.TrackerObjects> getInitialPairs() {
if (trackedObjects.isEmpty()) { if (trackedObjects.isEmpty()) {
return Optional.empty(); return Optional.empty();