Пинг и потери: считаем сами, потому что считать нечем
Вендор заменил сетевой слой на свой Netty-обработчик, поля задержки в нём нет, а сам класс в маппингах не восстановлен. Ванильный getLag() не достать, и игра пинг нигде не показывает. Остаётся то, что есть всегда: сервер шлёт keep-alive раз в 15 секунд по своему собственному расписанию. Отклонение интервала прихода - это и есть сеть, и скользящее среднее по нему даёт оценку на любом сервере. Грубые интервалы (потерянный пакет удваивает интервал) в среднее не попадают. Число помечается как оценка: Rsx.pingExact() false, в строке "ping~". Эхо со своим nonce в имени канала осталось в коде, но в этой сборке обработчик кастомного payload у клиента не найден, поэтому профиль его не объявляет и эхо просто недоступно - точность пока такая, какая есть. Период keep-alive читается из -Drsx.keepalivePeriod: прокси иногда шлют иначе, и стенду нужен короткий, чтобы проверить математику за секунды. Заодно: Resolver игнорировал "принудительный" скан и отдавал устаревший индекс замет позапрошенных классов. HUD-гейт читался в первый кадр и не находил экран. Стенд кормитkeep-alive с интервалом 240 мс при периоде 200 и ждёт оценку около 50 мс - ровно то отклонение, которое он и создал.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user