3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-07-29 16:48:09 +02:00

Ensure that exceptions in player event loop are handled

Any stray exception means that the entire event loop comes crashing down.
Dieser Commit ist enthalten in:
Camotoy 2021-08-17 20:57:46 -04:00
Ursprung 76399881a3
Commit 3d04a957d0
9 geänderte Dateien mit 57 neuen und 27 gelöschten Zeilen

Datei anzeigen

@ -161,7 +161,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override @Override
public boolean handle(ModalFormResponsePacket packet) { public boolean handle(ModalFormResponsePacket packet) {
session.getEventLoop().execute(() -> session.getFormCache().handleResponse(packet)); session.executeInEventLoop(() -> session.getFormCache().handleResponse(packet));
return true; return true;
} }

Datei anzeigen

@ -115,6 +115,7 @@ public class GeyserSession implements CommandSender {
private final UpstreamSession upstream; private final UpstreamSession upstream;
/** /**
* The loop where all packets and ticking is processed to prevent concurrency issues. * The loop where all packets and ticking is processed to prevent concurrency issues.
* If this is manually called, ensure that any exceptions are properly handled.
*/ */
private final EventLoop eventLoop; private final EventLoop eventLoop;
private TcpClientSession downstream; private TcpClientSession downstream;
@ -804,9 +805,8 @@ public class GeyserSession implements CommandSender {
@Override @Override
public void packetReceived(PacketReceivedEvent event) { public void packetReceived(PacketReceivedEvent event) {
if (!closed) { Packet packet = event.getPacket();
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(packet.getClass(), packet, GeyserSession.this);
}
} }
@Override @Override
@ -874,6 +874,32 @@ public class GeyserSession implements CommandSender {
disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.close", getClientData().getLanguageCode())); disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.close", getClientData().getLanguageCode()));
} }
/**
* Executes a task and prints a stack trace if an error occurs.
*/
public void executeInEventLoop(Runnable runnable) {
eventLoop.execute(() -> {
try {
runnable.run();
} catch (Throwable e) {
e.printStackTrace();
}
});
}
/**
* Schedules a task and prints a stack trace if an error occurs.
*/
public ScheduledFuture<?> scheduleInEventLoop(Runnable runnable, long duration, TimeUnit timeUnit) {
return eventLoop.schedule(() -> {
try {
runnable.run();
} catch (Throwable e) {
e.printStackTrace();
}
}, duration, timeUnit);
}
/** /**
* Called every 50 milliseconds - one Minecraft tick. * Called every 50 milliseconds - one Minecraft tick.
*/ */

Datei anzeigen

@ -87,27 +87,31 @@ public class PacketTranslatorRegistry<T> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) { public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
if (!session.getUpstream().isClosed() && !session.isClosed()) { if (!session.getUpstream().isClosed() && !session.isClosed()) {
try { PacketTranslator<P> translator = (PacketTranslator<P>) translators.get(clazz);
PacketTranslator<P> translator = (PacketTranslator<P>) translators.get(clazz); if (translator != null) {
if (translator != null) { EventLoop eventLoop = session.getEventLoop();
EventLoop eventLoop = session.getEventLoop(); if (eventLoop.inEventLoop()) {
if (eventLoop.inEventLoop()) { translate0(session, translator, packet);
translator.translate(packet, session);
} else {
eventLoop.execute(() -> translator.translate(packet, session));
}
return true;
} else { } else {
if ((GeyserConnector.getInstance().getPlatformType() != PlatformType.STANDALONE || !(packet instanceof BedrockPacket)) && !IGNORED_PACKETS.contains(clazz)) { eventLoop.execute(() -> translate0(session, translator, packet));
// Other debug logs already take care of Bedrock packets for us if on standalone }
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet)); return true;
} } else {
if ((GeyserConnector.getInstance().getPlatformType() != PlatformType.STANDALONE || !(packet instanceof BedrockPacket)) && !IGNORED_PACKETS.contains(clazz)) {
// Other debug logs already take care of Bedrock packets for us if on standalone
GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet));
} }
} catch (Throwable ex) {
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.packet.failed", packet.getClass().getSimpleName()), ex);
ex.printStackTrace();
} }
} }
return false; return false;
} }
private <P extends T> void translate0(GeyserSession session, PacketTranslator<P> translator, P packet) {
try {
translator.translate(packet, session);
} catch (Throwable ex) {
GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.packet.failed", packet.getClass().getSimpleName()), ex);
ex.printStackTrace();
}
}
} }

Datei anzeigen

@ -48,7 +48,7 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
switch (packet.getAction()) { switch (packet.getAction()) {
case SWING_ARM: case SWING_ARM:
// Delay so entity damage can be processed first // Delay so entity damage can be processed first
session.getEventLoop().schedule(() -> session.scheduleInEventLoop(() ->
session.sendDownstreamPacket(new ClientPlayerSwingArmPacket(Hand.MAIN_HAND)), session.sendDownstreamPacket(new ClientPlayerSwingArmPacket(Hand.MAIN_HAND)),
25, 25,
TimeUnit.MILLISECONDS TimeUnit.MILLISECONDS

Datei anzeigen

@ -220,7 +220,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
if (session.isSneaking() || blockState != BlockRegistries.JAVA_IDENTIFIERS.get("minecraft:crafting_table")) { if (session.isSneaking() || blockState != BlockRegistries.JAVA_IDENTIFIERS.get("minecraft:crafting_table")) {
// Delay the interaction in case the client doesn't intend to actually use the bucket // Delay the interaction in case the client doesn't intend to actually use the bucket
// See BedrockActionTranslator.java // See BedrockActionTranslator.java
session.setBucketScheduledFuture(session.getEventLoop().schedule(() -> { session.setBucketScheduledFuture(session.scheduleInEventLoop(() -> {
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
session.sendDownstreamPacket(itemPacket); session.sendDownstreamPacket(itemPacket);
}, 5, TimeUnit.MILLISECONDS)); }, 5, TimeUnit.MILLISECONDS));

Datei anzeigen

@ -53,7 +53,7 @@ public class BedrockEntityEventTranslator extends PacketTranslator<EntityEventPa
ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData()); ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData());
session.sendDownstreamPacket(selectTradePacket); session.sendDownstreamPacket(selectTradePacket);
session.getEventLoop().schedule(() -> { session.scheduleInEventLoop(() -> {
Entity villager = session.getPlayerEntity(); Entity villager = session.getPlayerEntity();
Inventory openInventory = session.getOpenInventory(); Inventory openInventory = session.getOpenInventory();
if (openInventory instanceof MerchantContainer) { if (openInventory instanceof MerchantContainer) {

Datei anzeigen

@ -78,7 +78,7 @@ public class JavaSetSlotTranslator extends PacketTranslator<ServerSetSlotPacket>
if (session.getCraftingGridFuture() != null) { if (session.getCraftingGridFuture() != null) {
session.getCraftingGridFuture().cancel(false); session.getCraftingGridFuture().cancel(false);
} }
session.setCraftingGridFuture(session.getEventLoop().schedule(() -> updateCraftingGrid(session, packet, inventory, translator), 150, TimeUnit.MILLISECONDS)); session.setCraftingGridFuture(session.scheduleInEventLoop(() -> updateCraftingGrid(session, packet, inventory, translator), 150, TimeUnit.MILLISECONDS));
GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); GeyserItemStack newItem = GeyserItemStack.from(packet.getItem());
if (packet.getWindowId() == 0 && !(translator instanceof PlayerInventoryTranslator)) { if (packet.getWindowId() == 0 && !(translator instanceof PlayerInventoryTranslator)) {

Datei anzeigen

@ -147,7 +147,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
if (session.getUpstream().isInitialized()) { if (session.getUpstream().isInitialized()) {
player.spawnEntity(session); player.spawnEntity(session);
SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.getEventLoop().schedule(() -> { SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> {
// Delay to minimize split-second "player" pop-in // Delay to minimize split-second "player" pop-in
player.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false); player.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false);
player.updateBedrockMetadata(session); player.updateBedrockMetadata(session);

Datei anzeigen

@ -79,7 +79,7 @@ public class InventoryUtils {
if (translator != null) { if (translator != null) {
translator.prepareInventory(session, inventory); translator.prepareInventory(session, inventory);
if (translator instanceof DoubleChestInventoryTranslator && !((Container) inventory).isUsingRealBlock()) { if (translator instanceof DoubleChestInventoryTranslator && !((Container) inventory).isUsingRealBlock()) {
session.getEventLoop().schedule(() -> { session.scheduleInEventLoop(() -> {
Inventory openInv = session.getOpenInventory(); Inventory openInv = session.getOpenInventory();
if (openInv != null && openInv.getId() == inventory.getId()) { if (openInv != null && openInv.getId() == inventory.getId()) {
translator.openInventory(session, inventory); translator.openInventory(session, inventory);