Optimize redundant entity tracker update
This commit is contained in:
parent
f0436fb466
commit
62bf757f00
|
@ -37,4 +37,8 @@ public interface ServerPlayerEntityBridge extends PlayerEntityBridge {
|
||||||
Entity bridge$changeDimension(ServerLevel world, PlayerTeleportEvent.TeleportCause cause);
|
Entity bridge$changeDimension(ServerLevel world, PlayerTeleportEvent.TeleportCause cause);
|
||||||
|
|
||||||
boolean bridge$initialized();
|
boolean bridge$initialized();
|
||||||
|
|
||||||
|
boolean bridge$isTrackerDirty();
|
||||||
|
|
||||||
|
void bridge$setTrackerDirty(boolean flag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
package io.izzel.arclight.common.bridge.core.world.server;
|
package io.izzel.arclight.common.bridge.core.world.server;
|
||||||
|
|
||||||
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.server.level.ServerEntity;
|
import net.minecraft.server.level.ServerEntity;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
||||||
public interface ChunkMap_TrackedEntityBridge {
|
public interface ChunkMap_TrackedEntityBridge {
|
||||||
|
|
||||||
ServerEntity bridge$getServerEntity();
|
ServerEntity bridge$getServerEntity();
|
||||||
|
|
||||||
|
Entity bridge$getEntity();
|
||||||
|
|
||||||
|
SectionPos bridge$getLastSectionPos();
|
||||||
|
|
||||||
|
void bridge$setLastSectionPos(SectionPos pos);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.izzel.arclight.common.mixin.core.server.level;
|
||||||
|
|
||||||
import io.izzel.arclight.common.bridge.core.world.ServerEntityBridge;
|
import io.izzel.arclight.common.bridge.core.world.ServerEntityBridge;
|
||||||
import io.izzel.arclight.common.bridge.core.world.server.ChunkMap_TrackedEntityBridge;
|
import io.izzel.arclight.common.bridge.core.world.server.ChunkMap_TrackedEntityBridge;
|
||||||
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerEntity;
|
import net.minecraft.server.level.ServerEntity;
|
||||||
import net.minecraft.server.network.ServerPlayerConnection;
|
import net.minecraft.server.network.ServerPlayerConnection;
|
||||||
|
@ -21,6 +22,8 @@ public abstract class ChunkMap_TrackedEntityMixin implements ChunkMap_TrackedEnt
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@Shadow @Final ServerEntity serverEntity;
|
@Shadow @Final ServerEntity serverEntity;
|
||||||
@Shadow @Final public Set<ServerPlayerConnection> seenBy;
|
@Shadow @Final public Set<ServerPlayerConnection> seenBy;
|
||||||
|
@Shadow @Final Entity entity;
|
||||||
|
@Shadow SectionPos lastSectionPos;
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
@Inject(method = "<init>", at = @At("RETURN"))
|
||||||
|
@ -32,4 +35,19 @@ public abstract class ChunkMap_TrackedEntityMixin implements ChunkMap_TrackedEnt
|
||||||
public ServerEntity bridge$getServerEntity() {
|
public ServerEntity bridge$getServerEntity() {
|
||||||
return this.serverEntity;
|
return this.serverEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entity bridge$getEntity() {
|
||||||
|
return this.entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SectionPos bridge$getLastSectionPos() {
|
||||||
|
return this.lastSectionPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$setLastSectionPos(SectionPos pos) {
|
||||||
|
this.lastSectionPos = pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package io.izzel.arclight.common.mixin.optimization.general.network;
|
||||||
|
|
||||||
|
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
|
||||||
|
import io.izzel.arclight.common.bridge.core.world.server.ChunkMap_TrackedEntityBridge;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectCollection;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||||
|
import net.minecraft.core.SectionPos;
|
||||||
|
import net.minecraft.server.level.ChunkMap;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerPlayerConnection;
|
||||||
|
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.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Mixin(ChunkMap.class)
|
||||||
|
public class ChunkMapMixin_Optimize {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
@Shadow @Final public Int2ObjectMap<ChunkMap.TrackedEntity> entityMap;
|
||||||
|
@Shadow @Final public ServerLevel level;
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Redirect(method = "move", at = @At(value = "INVOKE", remap = false, target = "Lit/unimi/dsi/fastutil/ints/Int2ObjectMap;values()Lit/unimi/dsi/fastutil/objects/ObjectCollection;"))
|
||||||
|
private ObjectCollection<ChunkMap.TrackedEntity> arclight$markDirty(Int2ObjectMap<ChunkMap.TrackedEntity> instance, ServerPlayer player) {
|
||||||
|
((ServerPlayerEntityBridge) player).bridge$setTrackerDirty(true);
|
||||||
|
return new ObjectArraySet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "tick()V", cancellable = true, at = @At("HEAD"))
|
||||||
|
private void arclight$optimizedTick(CallbackInfo ci) {
|
||||||
|
var list = new ArrayList<ChunkMap.TrackedEntity>(this.level.players().size());
|
||||||
|
|
||||||
|
for (var trackedEntity : this.entityMap.values()) {
|
||||||
|
var entity = ((ChunkMap_TrackedEntityBridge) trackedEntity).bridge$getEntity();
|
||||||
|
if (entity instanceof ServerPlayer player && ((ServerPlayerEntityBridge) player).bridge$isTrackerDirty()) {
|
||||||
|
list.add(trackedEntity);
|
||||||
|
((ServerPlayerEntityBridge) player).bridge$setTrackerDirty(false);
|
||||||
|
}
|
||||||
|
((ChunkMap_TrackedEntityBridge) trackedEntity).bridge$getServerEntity().sendChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var trackedEntity : this.entityMap.values()) {
|
||||||
|
var entity = ((ChunkMap_TrackedEntityBridge) trackedEntity).bridge$getEntity();
|
||||||
|
SectionPos lastSectionPos = ((ChunkMap_TrackedEntityBridge) trackedEntity).bridge$getLastSectionPos();
|
||||||
|
SectionPos newSectionPos = SectionPos.of(entity);
|
||||||
|
((ChunkMap_TrackedEntityBridge) trackedEntity).bridge$setLastSectionPos(newSectionPos);
|
||||||
|
if (entity instanceof ServerPlayer player) {
|
||||||
|
for (var otherTracker : list) {
|
||||||
|
var other = (ServerPlayer) ((ChunkMap_TrackedEntityBridge) otherTracker).bridge$getEntity();
|
||||||
|
if (other.getId() > entity.getId()) {
|
||||||
|
trackedEntity.updatePlayer(other);
|
||||||
|
otherTracker.updatePlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
boolean chunkChanged = !Objects.equals(lastSectionPos, newSectionPos);
|
||||||
|
if (chunkChanged) {
|
||||||
|
trackedEntity.updatePlayers(this.level.players());
|
||||||
|
} else {
|
||||||
|
for (var other : list) {
|
||||||
|
trackedEntity.updatePlayer((ServerPlayer) ((ChunkMap_TrackedEntityBridge) other).bridge$getEntity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mixin(ChunkMap.TrackedEntity.class)
|
||||||
|
public static class TrackedEntityMixin {
|
||||||
|
|
||||||
|
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Sets;newIdentityHashSet()Ljava/util/Set;"))
|
||||||
|
private Set<ServerPlayerConnection> arclight$useFastUtilSet() {
|
||||||
|
return new ReferenceOpenHashSet<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package io.izzel.arclight.common.mixin.optimization.general;
|
package io.izzel.arclight.common.mixin.optimization.general.network;
|
||||||
|
|
||||||
import io.netty.util.concurrent.AbstractEventExecutor;
|
import io.netty.util.concurrent.AbstractEventExecutor;
|
||||||
import net.minecraft.network.Connection;
|
import net.minecraft.network.Connection;
|
|
@ -0,0 +1,29 @@
|
||||||
|
package io.izzel.arclight.common.mixin.optimization.general.network;
|
||||||
|
|
||||||
|
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
|
||||||
|
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
|
||||||
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
|
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.Redirect;
|
||||||
|
|
||||||
|
@Mixin(ServerGamePacketListenerImpl.class)
|
||||||
|
public class ServerGamePacketListenerImplMixin_Optimize {
|
||||||
|
|
||||||
|
@Shadow public ServerPlayer player;
|
||||||
|
|
||||||
|
@Redirect(method = "handleMovePlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;move(Lnet/minecraft/server/level/ServerPlayer;)V"))
|
||||||
|
private void arclight$markTrackerDirty(ServerChunkCache instance, ServerPlayer player, ServerboundMovePlayerPacket packet) {
|
||||||
|
if (!packet.hasPosition()) {
|
||||||
|
// do not update tracker when no position is updated
|
||||||
|
var old = ((ServerPlayerEntityBridge) this.player).bridge$isTrackerDirty();
|
||||||
|
instance.move(player);
|
||||||
|
((ServerPlayerEntityBridge) this.player).bridge$setTrackerDirty(old);
|
||||||
|
} else {
|
||||||
|
instance.move(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package io.izzel.arclight.common.mixin.optimization.general.network;
|
||||||
|
|
||||||
|
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
|
||||||
|
@Mixin(ServerPlayer.class)
|
||||||
|
public abstract class ServerPlayerMixin_Optimize implements ServerPlayerEntityBridge {
|
||||||
|
|
||||||
|
@Unique private boolean trackerDirty;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean bridge$isTrackerDirty() {
|
||||||
|
return this.trackerDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridge$setTrackerDirty(boolean flag) {
|
||||||
|
this.trackerDirty = flag;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,6 @@
|
||||||
"compatibilityLevel": "JAVA_11",
|
"compatibilityLevel": "JAVA_11",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"ClassInheritanceMultiMapMixin",
|
"ClassInheritanceMultiMapMixin",
|
||||||
"ConnectionMixin_Optimize",
|
|
||||||
"EntityDataManagerMixin_Optimize",
|
"EntityDataManagerMixin_Optimize",
|
||||||
"EntityMixin_Optimize",
|
"EntityMixin_Optimize",
|
||||||
"GoalMixin",
|
"GoalMixin",
|
||||||
|
@ -23,6 +22,11 @@
|
||||||
"activationrange.entity.ItemEntityMixin_ActivationRange",
|
"activationrange.entity.ItemEntityMixin_ActivationRange",
|
||||||
"activationrange.entity.LivingEntityMixin_ActivationRange",
|
"activationrange.entity.LivingEntityMixin_ActivationRange",
|
||||||
"activationrange.entity.VillagerEntityMixin_ActivationRange",
|
"activationrange.entity.VillagerEntityMixin_ActivationRange",
|
||||||
|
"network.ChunkMapMixin_Optimize",
|
||||||
|
"network.ChunkMapMixin_Optimize$TrackedEntityMixin",
|
||||||
|
"network.ConnectionMixin_Optimize",
|
||||||
|
"network.ServerGamePacketListenerImplMixin_Optimize",
|
||||||
|
"network.ServerPlayerMixin_Optimize",
|
||||||
"realtime.ItemEntityMixin_Realtime",
|
"realtime.ItemEntityMixin_Realtime",
|
||||||
"realtime.PlayerInteractionManagerMixin_Realtime",
|
"realtime.PlayerInteractionManagerMixin_Realtime",
|
||||||
"trackingrange.ChunkManagerMixin_TrackingRange"
|
"trackingrange.ChunkManagerMixin_TrackingRange"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user