b5ffe0e9d7
Вендор заменил сетевой слой на свой Netty-обработчик, поля задержки в нём нет, а сам класс в маппингах не восстановлен. Ванильный getLag() не достать, и игра пинг нигде не показывает. Остаётся то, что есть всегда: сервер шлёт keep-alive раз в 15 секунд по своему собственному расписанию. Отклонение интервала прихода - это и есть сеть, и скользящее среднее по нему даёт оценку на любом сервере. Грубые интервалы (потерянный пакет удваивает интервал) в среднее не попадают. Число помечается как оценка: Rsx.pingExact() false, в строке "ping~". Эхо со своим nonce в имени канала осталось в коде, но в этой сборке обработчик кастомного payload у клиента не найден, поэтому профиль его не объявляет и эхо просто недоступно - точность пока такая, какая есть. Период keep-alive читается из -Drsx.keepalivePeriod: прокси иногда шлют иначе, и стенду нужен короткий, чтобы проверить математику за секунды. Заодно: Resolver игнорировал "принудительный" скан и отдавал устаревший индекс замет позапрошенных классов. HUD-гейт читался в первый кадр и не находил экран. Стенд кормитkeep-alive с интервалом 240 мс при периоде 200 и ждёт оценку около 50 мс - ровно то отклонение, которое он и создал.
68 lines
2.2 KiB
Java
68 lines
2.2 KiB
Java
package rsx;
|
|
|
|
/**
|
|
* Builds the echo packet.
|
|
*
|
|
* The nonce travels in the packet's channel name, so no payload buffer has to
|
|
* be built or parsed: a server that supports the mod echoes the channel back
|
|
* and the client recognises its own echo by the name.
|
|
*
|
|
* The packet class is vendor code with no stable name, so the profile has to
|
|
* carry it. When it does not, the echo is simply unavailable and the modloader
|
|
* falls back to the keep-alive estimate - which is why nothing here fails loudly
|
|
* on a build it does not recognise.
|
|
*/
|
|
public final class EchoPacket {
|
|
|
|
public static final String CHANNEL = "rsx_echo";
|
|
|
|
private EchoPacket() {
|
|
}
|
|
|
|
/**
|
|
* @return a packet carrying the nonce, or null when this build has no echo
|
|
*/
|
|
public static Object create(Object netHandlerPlayClient, int nonce) {
|
|
Profile p = Resolver.profile();
|
|
if (p == null) {
|
|
return null;
|
|
}
|
|
String[] ctor = p.member("rsx.net.echoPacket", "ctor");
|
|
if (ctor == null) {
|
|
return null;
|
|
}
|
|
try {
|
|
Class<?> cls = Resolver.findLoaded(p.obf("rsx.net.echoPacket"));
|
|
if (cls == null) {
|
|
return null;
|
|
}
|
|
Class<?> buffer = Resolver.findLoaded(
|
|
p.obf("rsx.net.echoBuffer"));
|
|
java.lang.reflect.Constructor<?> c = cls.getDeclaredConstructor(
|
|
String.class, buffer);
|
|
c.setAccessible(true);
|
|
return c.newInstance(CHANNEL + ":" + nonce, null);
|
|
} catch (Throwable t) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/** The nonce from a channel name, or -1 when it is not ours. */
|
|
public static int nonceOf(String channel) {
|
|
if (channel == null || !channel.startsWith(CHANNEL + ":")) {
|
|
return -1;
|
|
}
|
|
try {
|
|
return Integer.parseInt(channel.substring(CHANNEL.length() + 1));
|
|
} catch (Throwable t) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/** True when this build can send an echo at all. */
|
|
public static boolean available() {
|
|
Profile p = Resolver.profile();
|
|
return p != null && p.member("rsx.net.echoPacket", "ctor") != null;
|
|
}
|
|
}
|