Clean up player capabilities networking

This commit is contained in:
Sollace 2024-05-22 01:04:12 +01:00
parent d824d5d701
commit 9e2135fde3
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
10 changed files with 88 additions and 97 deletions

View file

@ -103,7 +103,6 @@ public class PlaceableSpell extends AbstractDelegatingSpell implements OrientedS
@Override @Override
public boolean tick(Caster<?> source, Situation situation) { public boolean tick(Caster<?> source, Situation situation) {
System.out.println("Placed Tick: " + source + " " + source.isClient() + " " + situation);
if (situation == Situation.BODY) { if (situation == Situation.BODY) {
if (!source.isClient()) { if (!source.isClient()) {
if (dimension == null) { if (dimension == null) {

View file

@ -102,7 +102,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
private final ItemTracker armour = addTicker(new ItemTracker(this)); private final ItemTracker armour = addTicker(new ItemTracker(this));
private final Transportation<T> transportation = new Transportation<>(this); private final Transportation<T> transportation = new Transportation<>(this);
private final DataTrackerManager trackers; protected final DataTrackerManager trackers;
protected final DataTracker tracker; protected final DataTracker tracker;
protected final DataTracker.Entry<UUID> carrierId; protected final DataTracker.Entry<UUID> carrierId;
@ -487,6 +487,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
public void toNBT(NbtCompound compound) { public void toNBT(NbtCompound compound) {
enchants.toNBT(compound); enchants.toNBT(compound);
spells.getSlots().toNBT(compound); spells.getSlots().toNBT(compound);
getCarrierId().ifPresent(id -> compound.putUuid("carrier", id));
toSyncronisedNbt(compound); toSyncronisedNbt(compound);
} }
@ -494,19 +495,18 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
public void fromNBT(NbtCompound compound) { public void fromNBT(NbtCompound compound) {
enchants.fromNBT(compound); enchants.fromNBT(compound);
spells.getSlots().fromNBT(compound); spells.getSlots().fromNBT(compound);
setCarrier(compound.containsUuid("carrier") ? compound.getUuid("carrier") : null);
fromSynchronizedNbt(compound); fromSynchronizedNbt(compound);
} }
@Override @Override
public void toSyncronisedNbt(NbtCompound compound) { public void toSyncronisedNbt(NbtCompound compound) {
compound.put("armour", armour.toNBT()); compound.put("armour", armour.toNBT());
getCarrierId().ifPresent(id -> compound.putUuid("carrier", id));
} }
@Override @Override
public void fromSynchronizedNbt(NbtCompound compound) { public void fromSynchronizedNbt(NbtCompound compound) {
armour.fromNBT(compound.getCompound("armour")); armour.fromNBT(compound.getCompound("armour"));
setCarrier(compound.containsUuid("carrier") ? compound.getUuid("carrier") : null);
} }
public void updateVelocity() { public void updateVelocity() {

View file

@ -111,6 +111,12 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
public Pony(PlayerEntity player) { public Pony(PlayerEntity player) {
super(player); super(player);
trackers.addPacketEmitter((sender, initial) -> {
if (initial || dirty) {
dirty = false;
sender.accept(Channel.SERVER_PLAYER_CAPABILITIES.toPacket(new MsgPlayerCapabilities(this)));
}
});
race = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); race = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN);
suppressedRace = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN); suppressedRace = this.tracker.startTracking(TrackableDataType.of(Race.PACKET_CODEC), Race.HUMAN);
this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP); this.levels = new PlayerLevelStore(this, tracker, true, USounds.Vanilla.ENTITY_PLAYER_LEVELUP);
@ -314,19 +320,6 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
dirty = true; dirty = true;
} }
private void sendCapabilities() {
if (!dirty) {
return;
}
dirty = false;
if (entity instanceof ServerPlayerEntity) {
MsgOtherPlayerCapabilities packet = new MsgOtherPlayerCapabilities(this);
Channel.SERVER_PLAYER_CAPABILITIES.sendToPlayer(packet, (ServerPlayerEntity)entity);
Channel.SERVER_OTHER_PLAYER_CAPABILITIES.sendToSurroundingPlayers(packet, entity);
}
}
public AbilityDispatcher getAbilities() { public AbilityDispatcher getAbilities() {
return powers; return powers;
} }
@ -582,8 +575,6 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
setSpecies(newRace); setSpecies(newRace);
} }
} }
sendCapabilities();
} }
@Override @Override
@ -825,10 +816,28 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
} }
@Override @Override
public void toSyncronisedNbt(NbtCompound compound) { public void toNBT(NbtCompound compound) {
super.toSyncronisedNbt(compound);
compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString()); compound.putString("playerSpecies", Race.REGISTRY.getId(getSpecies()).toString());
compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString()); compound.putString("suppressedSpecies", Race.REGISTRY.getId(getSuppressedRace()).toString());
compound.put("mana", mana.toNBT());
compound.putInt("levels", levels.get());
compound.putInt("corruption", corruption.get());
super.toNBT(compound);
}
@Override
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"));
corruption.set(compound.getInt("corruption"));
mana.fromNBT(compound.getCompound("mana"));
super.fromNBT(compound);
}
@Override
public void toSyncronisedNbt(NbtCompound compound) {
super.toSyncronisedNbt(compound);
compound.putFloat("magicExhaustion", magicExhaustion); compound.putFloat("magicExhaustion", magicExhaustion);
compound.putInt("ticksInSun", ticksInSun); compound.putInt("ticksInSun", ticksInSun);
compound.putBoolean("hasShades", hasShades); compound.putBoolean("hasShades", hasShades);
@ -837,12 +846,8 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
compound.put("gravity", gravity.toNBT()); compound.put("gravity", gravity.toNBT());
compound.put("charms", charms.toNBT()); compound.put("charms", charms.toNBT());
compound.put("discoveries", discoveries.toNBT()); compound.put("discoveries", discoveries.toNBT());
compound.put("mana", mana.toNBT());
compound.putInt("levels", levels.get());
compound.putInt("corruption", corruption.get());
compound.putInt("ticksInvulnerable", ticksInvulnerable); compound.putInt("ticksInvulnerable", ticksInvulnerable);
compound.putInt("ticksMetamorphising", ticksMetamorphising); compound.putInt("ticksMetamorphising", ticksMetamorphising);
NbtCompound progress = new NbtCompound(); NbtCompound progress = new NbtCompound();
advancementProgress.forEach((key, count) -> { advancementProgress.forEach((key, count) -> {
progress.putInt(key, count); progress.putInt(key, count);
@ -853,22 +858,16 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
@Override @Override
public void fromSynchronizedNbt(NbtCompound compound) { public void fromSynchronizedNbt(NbtCompound compound) {
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"));
discoveries.fromNBT(compound.getCompound("discoveries")); discoveries.fromNBT(compound.getCompound("discoveries"));
levels.set(compound.getInt("levels"));
corruption.set(compound.getInt("corruption"));
mana.fromNBT(compound.getCompound("mana"));
acrobatics.fromNBT(compound.getCompound("acrobatics")); acrobatics.fromNBT(compound.getCompound("acrobatics"));
magicExhaustion = compound.getFloat("magicExhaustion"); magicExhaustion = compound.getFloat("magicExhaustion");
ticksInvulnerable = compound.getInt("ticksInvulnerable"); ticksInvulnerable = compound.getInt("ticksInvulnerable");
ticksInSun = compound.getInt("ticksInSun"); ticksInSun = compound.getInt("ticksInSun");
hasShades = compound.getBoolean("hasShades"); hasShades = compound.getBoolean("hasShades");
ticksMetamorphising = compound.getInt("ticksMetamorphising"); ticksMetamorphising = compound.getInt("ticksMetamorphising");
NbtCompound progress = compound.getCompound("advancementProgress"); NbtCompound progress = compound.getCompound("advancementProgress");
advancementProgress.clear(); advancementProgress.clear();
for (String key : progress.getKeys()) { for (String key : progress.getKeys()) {

View file

@ -106,13 +106,6 @@ abstract class MixinEntity implements EntityDuck, Trackable {
} }
} }
@Inject(method = "tick()V", at = @At("RETURN"))
private void afterTick(CallbackInfo info) {
if (dataTrackerManager != null) {
dataTrackerManager.tick();
}
}
@Inject(method = "updatePassengerPosition(Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/Entity$PositionUpdater;)V", @Inject(method = "updatePassengerPosition(Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/Entity$PositionUpdater;)V",
at = @At("HEAD"), at = @At("HEAD"),
cancellable = true cancellable = true

View file

@ -21,9 +21,16 @@ import net.minecraft.server.network.ServerPlayerEntity;
abstract class MixinEntityTrackerEntry { abstract class MixinEntityTrackerEntry {
@Shadow @Shadow
private @Final Entity entity; private @Final Entity entity;
@Shadow
abstract void sendSyncPacket(Packet<?> packet);
@Inject(method = "tick()V", at = @At("TAIL"))
private void unicopia_onTick(CallbackInfo info) {
Trackable.of(entity).getDataTrackers().tick(this::sendSyncPacket);
}
@Inject(method = "sendPackets", at = @At("RETURN")) @Inject(method = "sendPackets", at = @At("RETURN"))
private void onSendPackets(ServerPlayerEntity player, Consumer<Packet<ClientPlayPacketListener>> sender, CallbackInfo info) { private void unicopia_onSendPackets(ServerPlayerEntity player, Consumer<Packet<ClientPlayPacketListener>> sender, CallbackInfo info) {
Trackable.of(entity).getDataTrackers().sendInitial(player, sender); Trackable.of(entity).getDataTrackers().sendInitial(player, sender);
} }
} }

View file

@ -33,8 +33,7 @@ public interface Channel {
S2CPacketType<MsgServerResources> SERVER_RESOURCES = SimpleNetworking.serverToClient(Unicopia.id("resources"), MsgServerResources::new); S2CPacketType<MsgServerResources> SERVER_RESOURCES = SimpleNetworking.serverToClient(Unicopia.id("resources"), MsgServerResources::new);
S2CPacketType<MsgTrackedValues> SERVER_TRACKED_ENTITY_DATA = SimpleNetworking.serverToClient(Unicopia.id("tracked_entity_date"), MsgTrackedValues::new); S2CPacketType<MsgTrackedValues> SERVER_TRACKED_ENTITY_DATA = SimpleNetworking.serverToClient(Unicopia.id("tracked_entity_date"), MsgTrackedValues::new);
S2CPacketType<MsgOtherPlayerCapabilities> SERVER_OTHER_PLAYER_CAPABILITIES = SimpleNetworking.serverToClient(Unicopia.id("other_player_capabilities"), MsgOtherPlayerCapabilities::new); S2CPacketType<MsgPlayerAnimationChange> SERVER_PLAYER_ANIMATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("player_animation_change"), MsgPlayerAnimationChange::new);
S2CPacketType<MsgPlayerAnimationChange> SERVER_PLAYER_ANIMATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("other_player_animation_change"), MsgPlayerAnimationChange::new);
S2CPacketType<MsgSkyAngle> SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new); S2CPacketType<MsgSkyAngle> SERVER_SKY_ANGLE = SimpleNetworking.serverToClient(Unicopia.id("sky_angle"), MsgSkyAngle::new);
S2CPacketType<MsgConfigurationChange> CONFIGURATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("config"), MsgConfigurationChange::new); S2CPacketType<MsgConfigurationChange> CONFIGURATION_CHANGE = SimpleNetworking.serverToClient(Unicopia.id("config"), MsgConfigurationChange::new);
S2CPacketType<MsgZapAppleStage> SERVER_ZAP_STAGE = SimpleNetworking.serverToClient(Unicopia.id("zap_stage"), MsgZapAppleStage::new); S2CPacketType<MsgZapAppleStage> SERVER_ZAP_STAGE = SimpleNetworking.serverToClient(Unicopia.id("zap_stage"), MsgZapAppleStage::new);

View file

@ -1,26 +0,0 @@
package com.minelittlepony.unicopia.network;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
/**
* Sent by the server to update other player's capabilities.
*/
public class MsgOtherPlayerCapabilities extends MsgPlayerCapabilities {
MsgOtherPlayerCapabilities(PacketByteBuf buffer) {
super(buffer);
}
public MsgOtherPlayerCapabilities(Pony player) {
super(player);
}
@Override
protected Pony getRecipient(PlayerEntity sender) {
return Pony.of(MinecraftClient.getInstance().world.getPlayerByUuid(playerId));
}
}

View file

@ -3,9 +3,6 @@ package com.minelittlepony.unicopia.network;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.UUID;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.sollace.fabwork.api.packets.HandledPacket; import com.sollace.fabwork.api.packets.HandledPacket;
@ -23,12 +20,12 @@ import net.minecraft.nbt.NbtIo;
*/ */
public class MsgPlayerCapabilities implements HandledPacket<PlayerEntity> { public class MsgPlayerCapabilities implements HandledPacket<PlayerEntity> {
protected final UUID playerId; protected final int playerId;
private final NbtCompound compoundTag; private final NbtCompound compoundTag;
MsgPlayerCapabilities(PacketByteBuf buffer) { MsgPlayerCapabilities(PacketByteBuf buffer) {
playerId = buffer.readUuid(); playerId = buffer.readInt();
try (InputStream in = new ByteBufInputStream(buffer)) { try (InputStream in = new ByteBufInputStream(buffer)) {
compoundTag = NbtIo.readCompressed(in); compoundTag = NbtIo.readCompressed(in);
} catch (IOException e) { } catch (IOException e) {
@ -37,14 +34,14 @@ public class MsgPlayerCapabilities implements HandledPacket<PlayerEntity> {
} }
public MsgPlayerCapabilities(Pony player) { public MsgPlayerCapabilities(Pony player) {
playerId = player.asEntity().getUuid(); playerId = player.asEntity().getId();
compoundTag = new NbtCompound(); compoundTag = new NbtCompound();
player.toSyncronisedNbt(compoundTag); player.toSyncronisedNbt(compoundTag);
} }
@Override @Override
public void toBuffer(PacketByteBuf buffer) { public void toBuffer(PacketByteBuf buffer) {
buffer.writeUuid(playerId); buffer.writeInt(playerId);
try (OutputStream out = new ByteBufOutputStream(buffer)) { try (OutputStream out = new ByteBufOutputStream(buffer)) {
NbtIo.writeCompressed(compoundTag, out); NbtIo.writeCompressed(compoundTag, out);
} catch (IOException e) { } catch (IOException e) {
@ -53,16 +50,9 @@ public class MsgPlayerCapabilities implements HandledPacket<PlayerEntity> {
@Override @Override
public void handle(PlayerEntity sender) { public void handle(PlayerEntity sender) {
Pony player = getRecipient(sender); Pony player = Pony.of(sender.getWorld().getEntityById(playerId)).orElse(null);
if (player == null) { if (player != null) {
Unicopia.LOGGER.warn("Skipping capabilities for unknown player " + playerId.toString());
return;
}
player.fromSynchronizedNbt(compoundTag); player.fromSynchronizedNbt(compoundTag);
} }
protected Pony getRecipient(PlayerEntity sender) {
return Pony.of(sender);
} }
} }

View file

@ -5,29 +5,39 @@ import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.minelittlepony.unicopia.network.Channel; import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.util.Tickable;
import com.minelittlepony.unicopia.network.Channel;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.network.listener.ClientPlayPacketListener; import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.Packet;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
public class DataTrackerManager implements Tickable { public class DataTrackerManager {
private final Entity entity; private final Entity entity;
final boolean isClient; final boolean isClient;
private final List<DataTracker> trackers = new ObjectArrayList<>(); private final List<DataTracker> trackers = new ObjectArrayList<>();
private final List<ObjectTracker<?>> objectTrackers = new ObjectArrayList<>(); private final List<ObjectTracker<?>> objectTrackers = new ObjectArrayList<>();
private final DataTracker primaryTracker = checkoutTracker(); private final List<PacketEmitter> packetEmitters = new ObjectArrayList<>();
@Nullable
private DataTracker primaryTracker;
public DataTrackerManager(Entity entity) { public DataTrackerManager(Entity entity) {
this.entity = entity; this.entity = entity;
this.isClient = entity.getWorld().isClient; this.isClient = entity.getWorld().isClient;
} }
public synchronized void addPacketEmitter(PacketEmitter packetEmitter) {
packetEmitters.add(packetEmitter);
}
public DataTracker getPrimaryTracker() { public DataTracker getPrimaryTracker() {
if (primaryTracker == null) {
primaryTracker = checkoutTracker();
}
return primaryTracker; return primaryTracker;
} }
@ -43,13 +53,16 @@ public class DataTrackerManager implements Tickable {
return tracker; return tracker;
} }
@Override public void tick(Consumer<Packet<?>> sender) {
public void tick() { synchronized (this) {
if (isClient) { for (var emitter : packetEmitters) {
emitter.sendPackets(sender, false);
}
if (trackers.isEmpty() && objectTrackers.isEmpty()) {
return; return;
} }
synchronized (this) {
List<MsgTrackedValues.TrackerEntries> toTransmit = new ArrayList<>(); List<MsgTrackedValues.TrackerEntries> toTransmit = new ArrayList<>();
List<MsgTrackedValues.TrackerObjects> objToTransmit = new ArrayList<>(); List<MsgTrackedValues.TrackerObjects> objToTransmit = new ArrayList<>();
@ -62,13 +75,22 @@ public class DataTrackerManager implements Tickable {
objToTransmit, objToTransmit,
toTransmit toTransmit
); );
Channel.SERVER_TRACKED_ENTITY_DATA.sendToSurroundingPlayers(packet, entity); sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(packet));
} }
} }
} }
@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) {
for (var emitter : packetEmitters) {
emitter.sendPackets((Consumer)sender, true);
}
if (trackers.isEmpty() && objectTrackers.isEmpty()) {
return;
}
List<MsgTrackedValues.TrackerEntries> toTransmit = new ArrayList<>(); List<MsgTrackedValues.TrackerEntries> toTransmit = new ArrayList<>();
List<MsgTrackedValues.TrackerObjects> objToTransmit = new ArrayList<>(); List<MsgTrackedValues.TrackerObjects> objToTransmit = new ArrayList<>();
@ -100,4 +122,8 @@ public class DataTrackerManager implements Tickable {
} }
} }
} }
public interface PacketEmitter {
void sendPackets(Consumer<Packet<?>> consumer, boolean initial);
}
} }

View file

@ -135,7 +135,11 @@ public class ObjectTracker<T extends TrackableObject> implements NbtSerialisable
Map<UUID, T> values = new Object2ObjectOpenHashMap<>(); Map<UUID, T> values = new Object2ObjectOpenHashMap<>();
compound.getKeys().forEach(key -> { compound.getKeys().forEach(key -> {
try { try {
UUID id = UUID.fromString(key); UUID id = Util.NIL_UUID;
try {
id = UUID.fromString(key);
} catch (Throwable ignore) {}
if (id != null && !Util.NIL_UUID.equals(id)) { if (id != null && !Util.NIL_UUID.equals(id)) {
NbtCompound nbt = compound.getCompound(key); NbtCompound nbt = compound.getCompound(key);
T entry = constructor.get(); T entry = constructor.get();
@ -143,7 +147,7 @@ public class ObjectTracker<T extends TrackableObject> implements NbtSerialisable
values.put(id, entry); values.put(id, entry);
} }
} catch (Throwable t) { } catch (Throwable t) {
Unicopia.LOGGER.warn("Exception loading tracked object", t); Unicopia.LOGGER.warn("Exception loading tracked object: {}", t.getMessage());
} }
}); });
synchronized (this) { synchronized (this) {