-
Notifications
You must be signed in to change notification settings - Fork 0
Report about network cost about two model plugin (ModelEngine, BetterModel)
正如您所知,ModelEngine 和 BetterModel 都使用物品显示数据包。
因此,我们需要对 minecraft_set_entity_data 数据包进行性能分析,以假设网络使用情况。
这个数据包发送一些实体的数据列表。
- 共享特性
- 实体的原始特性
物品显示也有这个实体数据。
- 物品
- 变换(位置、旋转、缩放)
- 发光、插值持续时间/延迟、旗帜、亮度等。
您可以很容易地估计,变换相关的实体数据可能会非常重,消耗大量网络资源。
仅从特定模型插件派生的最终缓冲区大小进行性能分析非常困难。
但我们可以通过 Netty 通道注入来估算。
@SuppressWarnings("unused")
public final class ModelProfiler extends JavaPlugin {
private static final DecimalFormat FORMAT = new DecimalFormat("#,###");
private static final String VANILLA_ENCODER = "encoder";
private static final Method ENCODE_METHOD;
static {
try {
ENCODE_METHOD = MessageToByteEncoder.class
.getDeclaredMethod("encode", ChannelHandlerContext.class, Object.class, ByteBuf.class);
ENCODE_METHOD.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private final Map<UUID, PlayerProfiler> profilerMap = new ConcurrentHashMap<>();
@Override
public void onEnable() {
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void join(PlayerJoinEvent event) {
var player = event.getPlayer();
var channel = ((CraftPlayer) player).getHandle().connection.connection.channel;
channel.eventLoop().submit(() -> profilerMap.computeIfAbsent(player.getUniqueId(), uuid -> new PlayerProfiler(player, channel.pipeline())));
}
@EventHandler
public void quit(PlayerQuitEvent event) {
var handler = profilerMap.remove(event.getPlayer().getUniqueId());
if (handler != null) handler.remove();
}
}, this);
}
private record TimedPacketSize(long time, int bytes) {}
private class PlayerProfiler extends MessageToByteEncoder<Packet<?>> {
private final Queue<TimedPacketSize> byteQueue = new ConcurrentLinkedQueue<>();
private final ScheduledTask actionbar;
private final MessageToByteEncoder<?> delegate;
private PlayerProfiler(@NotNull Player player, @NotNull ChannelPipeline pipeline) {
actionbar = Bukkit.getAsyncScheduler().runAtFixedRate(ModelProfiler.this, task -> {
var time = System.currentTimeMillis();
byteQueue.removeIf(t -> time - t.time > 1000);
if (!byteQueue.isEmpty()) {
player.sendActionBar(Component.text("当前流量使用: " + FORMAT.format(byteQueue.stream()
.mapToInt(i -> i.bytes)
.sum() / 1024) + " kB/s"));
}
}, 50, 50, TimeUnit.MILLISECONDS);
delegate = (MessageToByteEncoder<?>) pipeline.replace(VANILLA_ENCODER, VANILLA_ENCODER, this);
}
private void remove() {
actionbar.cancel();
}
@Override
protected void encode(ChannelHandlerContext ctx, Packet<?> msg, ByteBuf out) throws Exception {
var before = out.writerIndex();
ENCODE_METHOD.invoke(delegate, ctx, msg, out);
if (msg instanceof ClientboundSetEntityDataPacket) {
byteQueue.add(new TimedPacketSize(System.currentTimeMillis(), out.writerIndex() - before));
}
}
}
}如您所见,它可以过滤所有 ClientboundSetEntityDataPacket 并收集每个玩家的原始数据包缓冲区大小。
它不是完全准确的网络资源使用情况,但它可以是一个检查某些模型插件效率的好工具。
- 上面的 ModelProfiler
- TrafficProfiler 1.2
- 由 torotoro 创建的 Soul Knight
- 以灵魂骑士的身份召唤傀儡,测试空闲和伤害着色
- 生产 5 个灵魂骑士并运行 90 秒以获取网络摘要
您可以在 我的 Youtube 上看到我的性能分析视频。
一般来说,ModelEngine 的流量是稳定的且较高的。
即使在空闲状态下,它也会使用大约 >=20kb 的数据包。
{
"total_time": "90002.0ms",
"average_traffic": {
"in": "0kbps",
"out": "449kbps"
},
"global": {
"client_bound": {
"minecraft_level_chunk_with_light": {
"value": 26878,
"percentage": "66.41%"
},
"minecraft_set_entity_data": {
"value": 10802,
"percentage": "26.69%"
},
"minecraft_entity_position_sync": {
"value": 2009,
"percentage": "4.965%"
},
"..."
}
}
}90 秒的摘要是 10,802kb 的数据,和 2,009 个位置同步数据包。 (=12,811kb)
您可以在 我的 Youtube 上看到我的性能分析视频。
一般来说,BetterModel 的流量是动态的(低 ~ 中等高)。
但在所有动画中,它比 ModelEngine 的数据包使用量更低。
{
"total_time": "90002.0ms",
"average_traffic": {
"in": "0kbps",
"out": "449kbps"
},
"global": {
"client_bound": {
"minecraft_level_chunk_with_light": {
"value": 27780,
"percentage": "84.286%"
},
"minecraft_set_entity_data": {
"value": 3769,
"percentage": "11.436%"
},
"minecraft_move_entity_rot": {
"value": 338,
"percentage": "1.027%"
},
"..."
}
}
}90 秒的摘要是 3,769kb 的数据,和 338 个旋转数据包。 (=4,107kb)
您可以看到,BetterModel 消耗的 32.05% 数据包大小与 ModelEngine 相比。
ModelEngine
数据包使用量稳定但持续较高。
例如,空闲动画产生的流量与行走动画几乎相同。
视锥剔除似乎效率不高。
它会响应玩家的偏航,但未能正确考虑俯仰,导致即使模型不可见也会产生不必要的网络流量。
BetterModel
数据包使用量较低且更动态。
空闲动画产生的流量比行走动画少一半。
总体而言,所有动画产生的流量比 ModelEngine 中的流量显著少。
似乎 BetterModel 比 ModelEngine 更优化网络使用。
也许它是一个减少网络成本的好选择。