Class PlayerEventManager
- All Implemented Interfaces:
org.bukkit.event.Listener
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate booleanWhether this instance has already hooked itself into the Bukkit event system.private UltiPanelWebSocketClientMust be volatile. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprivate StringgetServerId(UltiPanelWebSocketClient client) Gets the server ID.voidinitialize(UltiPanelWebSocketClient client) Initializes the player event manager.(package private) booleanLets tests assert the idempotency guard's state.voidonPlayerChangedWorld(org.bukkit.event.player.PlayerChangedWorldEvent event) Handles the player-world-change event.voidonPlayerChat(org.bukkit.event.player.PlayerChatEvent event) Handles the player-chat event.voidonPlayerCommandPreprocess(org.bukkit.event.player.PlayerCommandPreprocessEvent event) Handles the player-command event.voidonPlayerDeath(org.bukkit.event.entity.PlayerDeathEvent event) Handles the player-death event.voidonPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) Handles the player-join event.voidonPlayerKick(org.bukkit.event.player.PlayerKickEvent event) Handles the player-kick event.voidonPlayerQuit(org.bukkit.event.player.PlayerQuitEvent event) Handles the player-quit event.private voidIdempotently registers the event listener: returns immediately if already registered.private voidsendPlayerEvent(UltiPanelWebSocketClient client, com.google.gson.JsonObject data) Sends a player event to UltiPanel.voidshutdown()Unregisters the event listener and detaches the association with the client.
-
Field Details
-
webSocketClient
Must be volatile. Written on the WebSocket's onOpen thread (initialize(com.ultikits.ultitools.websocket.UltiPanelWebSocketClient)), read on the Bukkit main thread (the seven event handlers). Addingsynchronizedonly to the writer does not establish publication -- the reader never acquires the same monitor, so there is no happens-before edge between the two sides.This was accidentally masked before the idempotency guard was added: back then every
initializecall also calledregisterEvents, and Bukkit's own listener registration writes a volatile field onHandlerList, which event dispatch then reads -- so this field's write got piggybacked out for free. Once the guard started skipping registration, that piggyback chain broke: after a reconnect, the handler could keep looking at the old, already-disconnected client, and player events would be silently dropped. See the PR #264 review. -
listenerRegistered
private volatile boolean listenerRegisteredWhether this instance has already hooked itself into the Bukkit event system.initialize(UltiPanelWebSocketClient)is called byinitializeManagers(), which is itself hung on the WebSocket'sonConnectHandler-- it runs on every single onOpen. Without this guard, N disconnect-reconnect cycles would register N copies of the listener, and the same player event would be sent out N times. See issue #180.
-
-
Constructor Details
-
PlayerEventManager
public PlayerEventManager()
-
-
Method Details
-
initialize
Initializes the player event manager.The whole method is mutually exclusive with
shutdown(). Synchronizing onlyregisterEventson its own is not enough: a window would be left between "assign the client" and "register the listener", and if a logout happens to land exactly in that window, the listenershutdown()just detached would get reinstalled by theregisterEventsthat follows right behind it -- leavinglistenerRegisteredtrue even afterdisableCloud(). See the PR #264 review.- Parameters:
client- the WebSocket client
-
registerEvents
private void registerEvents()Idempotently registers the event listener: returns immediately if already registered.The caller must already hold this object's monitor lock (currently the only caller is
initialize(com.ultikits.ultitools.websocket.UltiPanelWebSocketClient)). -
shutdown
public void shutdown()Unregisters the event listener and detaches the association with the client.Called by
PluginInitiationUtils.disableCloud()-- i.e. after/ulticloud logout. Distinct from a "disconnect-and-reconnect": in that caseinitializegets called back afterward, so unregistering would just mean re-registering again; this method handles the case where the cloud feature was explicitly turned off, and the listener should genuinely be detached. -
isListenerRegistered
boolean isListenerRegistered()Lets tests assert the idempotency guard's state. -
onPlayerJoin
public void onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) Handles the player-join event. -
onPlayerQuit
public void onPlayerQuit(org.bukkit.event.player.PlayerQuitEvent event) Handles the player-quit event. -
onPlayerChat
public void onPlayerChat(org.bukkit.event.player.PlayerChatEvent event) Handles the player-chat event. -
onPlayerDeath
public void onPlayerDeath(org.bukkit.event.entity.PlayerDeathEvent event) Handles the player-death event.Moved here from the former
EnhancedPlayerEventListener(#387). That class carried@EventListenerbut was never registered, so this handler and the three below had never fired. Registering that class alongside this one was not an option: both emitted the sameplayer_eventmessage type, so join/quit/chat would have been sent twice. -
onPlayerKick
public void onPlayerKick(org.bukkit.event.player.PlayerKickEvent event) Handles the player-kick event. -
onPlayerCommandPreprocess
public void onPlayerCommandPreprocess(org.bukkit.event.player.PlayerCommandPreprocessEvent event) Handles the player-command event. -
onPlayerChangedWorld
public void onPlayerChangedWorld(org.bukkit.event.player.PlayerChangedWorldEvent event) Handles the player-world-change event. -
sendPlayerEvent
Sends a player event to UltiPanel.The client is passed in by the caller rather than re-reading
webSocketClienthere: each of the seven event handlers reads that volatile field into a local variable once and threads it through from there. Otherwise "check the connection" and "actually send" could read two different values -- ifshutdown()happens to land in between, this would be an NPE.- Parameters:
client- the client the event handler read on entrydata- the event data
-
getServerId
Gets the server ID.Takes the UUID handed to the client at connect time (i.e.
CommonUtils.getUltiToolsUUID(), seePluginInitiationUtils.getPanelWebsocketClient), consistent with every sibling manager. Before #180, this returned a hardcoded placeholder string, meaning every server worldwide sent out itsplayer_eventclaiming the same identity, and the panel side had no way to route them.- Returns:
- the server ID
-