mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Ensure that exceptions in player event loop are handled
Any stray exception means that the entire event loop comes crashing down.
This commit is contained in:
parent
76399881a3
commit
3d04a957d0
9 changed files with 57 additions and 27 deletions
|
@ -161,7 +161,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public boolean handle(ModalFormResponsePacket packet) {
|
||||
session.getEventLoop().execute(() -> session.getFormCache().handleResponse(packet));
|
||||
session.executeInEventLoop(() -> session.getFormCache().handleResponse(packet));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ public class GeyserSession implements CommandSender {
|
|||
private final UpstreamSession upstream;
|
||||
/**
|
||||
* 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 TcpClientSession downstream;
|
||||
|
@ -804,9 +805,8 @@ public class GeyserSession implements CommandSender {
|
|||
|
||||
@Override
|
||||
public void packetReceived(PacketReceivedEvent event) {
|
||||
if (!closed) {
|
||||
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this);
|
||||
}
|
||||
Packet packet = event.getPacket();
|
||||
PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(packet.getClass(), packet, GeyserSession.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -874,6 +874,32 @@ public class GeyserSession implements CommandSender {
|
|||
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.
|
||||
*/
|
||||
|
|
|
@ -87,27 +87,31 @@ public class PacketTranslatorRegistry<T> {
|
|||
@SuppressWarnings("unchecked")
|
||||
public <P extends T> boolean translate(Class<? extends P> clazz, P packet, GeyserSession session) {
|
||||
if (!session.getUpstream().isClosed() && !session.isClosed()) {
|
||||
try {
|
||||
PacketTranslator<P> translator = (PacketTranslator<P>) translators.get(clazz);
|
||||
if (translator != null) {
|
||||
EventLoop eventLoop = session.getEventLoop();
|
||||
if (eventLoop.inEventLoop()) {
|
||||
translator.translate(packet, session);
|
||||
} else {
|
||||
eventLoop.execute(() -> translator.translate(packet, session));
|
||||
}
|
||||
return true;
|
||||
PacketTranslator<P> translator = (PacketTranslator<P>) translators.get(clazz);
|
||||
if (translator != null) {
|
||||
EventLoop eventLoop = session.getEventLoop();
|
||||
if (eventLoop.inEventLoop()) {
|
||||
translate0(session, translator, packet);
|
||||
} 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));
|
||||
}
|
||||
eventLoop.execute(() -> translate0(session, translator, 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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class BedrockAnimateTranslator extends PacketTranslator<AnimatePacket> {
|
|||
switch (packet.getAction()) {
|
||||
case SWING_ARM:
|
||||
// Delay so entity damage can be processed first
|
||||
session.getEventLoop().schedule(() ->
|
||||
session.scheduleInEventLoop(() ->
|
||||
session.sendDownstreamPacket(new ClientPlayerSwingArmPacket(Hand.MAIN_HAND)),
|
||||
25,
|
||||
TimeUnit.MILLISECONDS
|
||||
|
|
|
@ -220,7 +220,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||
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
|
||||
// See BedrockActionTranslator.java
|
||||
session.setBucketScheduledFuture(session.getEventLoop().schedule(() -> {
|
||||
session.setBucketScheduledFuture(session.scheduleInEventLoop(() -> {
|
||||
ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND);
|
||||
session.sendDownstreamPacket(itemPacket);
|
||||
}, 5, TimeUnit.MILLISECONDS));
|
||||
|
|
|
@ -53,7 +53,7 @@ public class BedrockEntityEventTranslator extends PacketTranslator<EntityEventPa
|
|||
ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData());
|
||||
session.sendDownstreamPacket(selectTradePacket);
|
||||
|
||||
session.getEventLoop().schedule(() -> {
|
||||
session.scheduleInEventLoop(() -> {
|
||||
Entity villager = session.getPlayerEntity();
|
||||
Inventory openInventory = session.getOpenInventory();
|
||||
if (openInventory instanceof MerchantContainer) {
|
||||
|
|
|
@ -78,7 +78,7 @@ public class JavaSetSlotTranslator extends PacketTranslator<ServerSetSlotPacket>
|
|||
if (session.getCraftingGridFuture() != null) {
|
||||
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());
|
||||
if (packet.getWindowId() == 0 && !(translator instanceof PlayerInventoryTranslator)) {
|
||||
|
|
|
@ -147,7 +147,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements
|
|||
if (session.getUpstream().isInitialized()) {
|
||||
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
|
||||
player.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false);
|
||||
player.updateBedrockMetadata(session);
|
||||
|
|
|
@ -79,7 +79,7 @@ public class InventoryUtils {
|
|||
if (translator != null) {
|
||||
translator.prepareInventory(session, inventory);
|
||||
if (translator instanceof DoubleChestInventoryTranslator && !((Container) inventory).isUsingRealBlock()) {
|
||||
session.getEventLoop().schedule(() -> {
|
||||
session.scheduleInEventLoop(() -> {
|
||||
Inventory openInv = session.getOpenInventory();
|
||||
if (openInv != null && openInv.getId() == inventory.getId()) {
|
||||
translator.openInventory(session, inventory);
|
||||
|
|
Loading…
Reference in a new issue