Synchronize initial data to the client when an entity starts being tracked

This commit is contained in:
Sollace 2024-05-22 00:16:12 +01:00
parent 88cf90842f
commit 2f0adac616
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
6 changed files with 89 additions and 20 deletions

View file

@ -0,0 +1,29 @@
package com.minelittlepony.unicopia.mixin.server;
import java.util.function.Consumer;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.network.track.Trackable;
import net.minecraft.entity.Entity;
import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.server.network.EntityTrackerEntry;
import net.minecraft.server.network.ServerPlayerEntity;
@Mixin(EntityTrackerEntry.class)
abstract class MixinEntityTrackerEntry {
@Shadow
private @Final Entity entity;
@Inject(method = "sendPackets", at = @At("RETURN"))
private void onSendPackets(ServerPlayerEntity player, Consumer<Packet<ClientPlayPacketListener>> sender, CallbackInfo info) {
Trackable.of(entity).getDataTrackers().sendInitial(player, sender);
}
}

View file

@ -66,8 +66,7 @@ public class DataTracker {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable private void updateTrackables() {
synchronized void getDirtyPairs(List<MsgTrackedValues.TrackerEntries> output) {
for (var entry : persistentObjects.int2ObjectEntrySet()) { for (var entry : persistentObjects.int2ObjectEntrySet()) {
int key = entry.getIntKey(); int key = entry.getIntKey();
TrackableObject.Status status = entry.getValue().getStatus(); TrackableObject.Status status = entry.getValue().getStatus();
@ -76,12 +75,23 @@ public class DataTracker {
dirtyIndices.add(key); dirtyIndices.add(key);
} }
} }
}
synchronized void getInitialPairs(List<MsgTrackedValues.TrackerEntries> output) {
updateTrackables();
output.add(new MsgTrackedValues.TrackerEntries(id, true, codecs));
}
@Nullable
synchronized void getDirtyPairs(List<MsgTrackedValues.TrackerEntries> output) {
if (initial) { if (initial) {
initial = false; initial = false;
dirtyIndices = new IntOpenHashSet(); dirtyIndices = new IntOpenHashSet();
output.add(new MsgTrackedValues.TrackerEntries(id, true, codecs)); getInitialPairs(output);
} else if (!dirtyIndices.isEmpty()) { } else {
updateTrackables();
if (!dirtyIndices.isEmpty()) {
IntSet toSend = dirtyIndices; IntSet toSend = dirtyIndices;
dirtyIndices = new IntOpenHashSet(); dirtyIndices = new IntOpenHashSet();
List<Pair<?>> pairs = new ArrayList<>(); List<Pair<?>> pairs = new ArrayList<>();
@ -91,6 +101,7 @@ public class DataTracker {
output.add(new MsgTrackedValues.TrackerEntries(id, false, pairs)); output.add(new MsgTrackedValues.TrackerEntries(id, false, pairs));
} }
} }
}
synchronized void load(MsgTrackedValues.TrackerEntries values) { synchronized void load(MsgTrackedValues.TrackerEntries values) {
if (values.wipe()) { if (values.wipe()) {

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.network.track;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.Channel;
@ -9,6 +10,9 @@ import com.minelittlepony.unicopia.util.Tickable;
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.packet.Packet;
import net.minecraft.server.network.ServerPlayerEntity;
public class DataTrackerManager implements Tickable { public class DataTrackerManager implements Tickable {
private final Entity entity; private final Entity entity;
@ -45,17 +49,12 @@ public class DataTrackerManager implements Tickable {
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<>();
synchronized (this) { for (var entry : trackers) entry.getDirtyPairs(toTransmit);
for (var entry : trackers) { for (var entry : objectTrackers) entry.getDirtyPairs(objToTransmit);
entry.getDirtyPairs(toTransmit);
}
for (var entry : objectTrackers) {
entry.getDirtyPairs(objToTransmit);
}
if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) { if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) {
MsgTrackedValues packet = new MsgTrackedValues( MsgTrackedValues packet = new MsgTrackedValues(
@ -68,6 +67,25 @@ public class DataTrackerManager implements Tickable {
} }
} }
public synchronized void sendInitial(ServerPlayerEntity player, Consumer<Packet<ClientPlayPacketListener>> sender) {
synchronized (this) {
List<MsgTrackedValues.TrackerEntries> toTransmit = new ArrayList<>();
List<MsgTrackedValues.TrackerObjects> objToTransmit = new ArrayList<>();
for (var entry : trackers) entry.getInitialPairs(toTransmit);
for (var entry : objectTrackers) entry.getInitialPairs(objToTransmit);
if (!toTransmit.isEmpty() || !objToTransmit.isEmpty()) {
MsgTrackedValues packet = new MsgTrackedValues(
entity.getId(),
objToTransmit,
toTransmit
);
sender.accept(Channel.SERVER_TRACKED_ENTITY_DATA.toPacket(packet));
}
}
}
synchronized void load(MsgTrackedValues packet) { synchronized void load(MsgTrackedValues packet) {
for (var update : packet.updatedTrackers()) { for (var update : packet.updatedTrackers()) {
DataTracker tracker = trackers.get(update.id()); DataTracker tracker = trackers.get(update.id());

View file

@ -73,6 +73,17 @@ public class ObjectTracker<T extends TrackableObject> implements NbtSerialisable
quickAccess = Map.copyOf(trackedObjects); quickAccess = Map.copyOf(trackedObjects);
} }
synchronized void getInitialPairs(List<MsgTrackedValues.TrackerObjects> output) {
if (!trackedObjects.isEmpty()) {
Map<UUID, NbtCompound> trackableCompounds = new HashMap<>();
quickAccess.entrySet().forEach(object -> {
trackableCompounds.put(object.getKey(), object.getValue().toTrackedNbt());
});
output.add(new MsgTrackedValues.TrackerObjects(id, Set.of(), trackableCompounds));
}
}
synchronized void getDirtyPairs(List<MsgTrackedValues.TrackerObjects> output) { synchronized void getDirtyPairs(List<MsgTrackedValues.TrackerObjects> output) {
if (!trackedObjects.isEmpty()) { if (!trackedObjects.isEmpty()) {
Map<UUID, NbtCompound> trackableCompounds = new HashMap<>(); Map<UUID, NbtCompound> trackableCompounds = new HashMap<>();

View file

@ -3,7 +3,6 @@ package com.minelittlepony.unicopia.network.track;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
public interface Trackable { public interface Trackable {
DataTrackerManager getDataTrackers(); DataTrackerManager getDataTrackers();
static Trackable of(Entity entity) { static Trackable of(Entity entity) {

View file

@ -51,6 +51,7 @@
"MixinWardenEntity", "MixinWardenEntity",
"MixinWorld", "MixinWorld",
"PointOfInterestTypesAccessor", "PointOfInterestTypesAccessor",
"server.MixinEntityTrackerEntry",
"server.MixinPlayerManager", "server.MixinPlayerManager",
"server.MixinServerPlayerEntity", "server.MixinServerPlayerEntity",
"server.MixinServerPlayNetworkHandler", "server.MixinServerPlayNetworkHandler",