From fc2b7b63a2336b2e9995ea9274e6dc5e0153221f Mon Sep 17 00:00:00 2001 From: Josh Roy <10731363+JRoy@users.noreply.github.com> Date: Mon, 11 May 2020 09:53:05 -0400 Subject: [PATCH] Save player logout times on shutdown (#3157) Properly save userdata and mark the player's last logout time when the server is shutting down. Fixes #2764. --- .../com/earth2me/essentials/Essentials.java | 11 +++- .../essentials/craftbukkit/ServerState.java | 66 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 Essentials/src/com/earth2me/essentials/craftbukkit/ServerState.java diff --git a/Essentials/src/com/earth2me/essentials/Essentials.java b/Essentials/src/com/earth2me/essentials/Essentials.java index e8d714eb0..d2428ee3d 100644 --- a/Essentials/src/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/com/earth2me/essentials/Essentials.java @@ -18,6 +18,7 @@ package com.earth2me.essentials; import com.earth2me.essentials.commands.*; +import com.earth2me.essentials.craftbukkit.ServerState; import com.earth2me.essentials.items.AbstractItemDb; import com.earth2me.essentials.items.CustomItemResolver; import com.earth2me.essentials.items.FlatItemDb; @@ -367,7 +368,15 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { user.setVanished(false); user.sendMessage(tl("unvanishedReload")); } - user.stopTransaction(); + if (ServerState.isStopping()) { + user.setLastLocation(); + if (!user.isHidden()) { + user.setLastLogout(System.currentTimeMillis()); + } + user.cleanup(); + } else { + user.stopTransaction(); + } } cleanupOpenInventories(); if (i18n != null) { diff --git a/Essentials/src/com/earth2me/essentials/craftbukkit/ServerState.java b/Essentials/src/com/earth2me/essentials/craftbukkit/ServerState.java new file mode 100644 index 000000000..8f9fef052 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/craftbukkit/ServerState.java @@ -0,0 +1,66 @@ +package com.earth2me.essentials.craftbukkit; + +import net.ess3.nms.refl.ReflUtil; +import org.bukkit.Bukkit; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class ServerState { + + private static final MethodHandle isStopping; //Only in Paper + private static final MethodHandle nmsHasStopped; + private static final MethodHandle nmsIsRunning; + private static final Object nmsServer; + + static { + MethodHandle isStoppingHandle = null; + MethodHandle nmsHasStoppedHandle = null; + MethodHandle nmsIsRunningHandle = null; + Object nmsServerObject = null; + try { + isStoppingHandle = MethodHandles.lookup().findStatic(Bukkit.class, "isStopping", MethodType.methodType(boolean.class)); + } catch (Throwable e) { + try { + Class nmsClass = ReflUtil.getNMSClass("MinecraftServer"); + if (nmsClass != null) { + nmsServerObject = ReflUtil.getMethodCached(nmsClass, "getServer").invoke(null); + nmsIsRunningHandle = MethodHandles.lookup().findVirtual(nmsClass, "isRunning", MethodType.methodType(boolean.class)); + nmsHasStoppedHandle = MethodHandles.lookup().findVirtual(nmsClass, "hasStopped", MethodType.methodType(boolean.class)); + } + } catch (Throwable ignored) { + } + } + isStopping = isStoppingHandle; + nmsHasStopped = nmsHasStoppedHandle; + nmsIsRunning = nmsIsRunningHandle; + nmsServer = nmsServerObject; + } + + public static boolean isStopping() { + boolean stopping = false; + if (isStopping != null) { + try { + stopping = (boolean) isStopping.invoke(); + } catch (Throwable t) { + t.printStackTrace(); + } + } else if (nmsServer != null) { + if (nmsHasStopped != null) { + try { + stopping = (boolean) nmsHasStopped.invokeExact(nmsServer); + } catch (Throwable t) { + t.printStackTrace(); + } + } else if (nmsIsRunning != null) { + try { + stopping = (boolean) nmsIsRunning.invokeExact(nmsServer); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + return stopping; + } +}